使子进程暂停,直到收到父进程执行执行任务的信号

时间:2018-08-06 12:26:11

标签: c signals fork execl

我正在根据问题Make children process wait until receiving parent's signal的答案尝试开发一个简单的铁路仿真。

我的任务:我有5个代表火车的过程。我需要通过fork()创建这5个进程(T1,T2,T3,T4和T5),并暂停每个进程,直到创建了所有进程。之后,父进程将向子进程发送信号,每个子进程将使用execl execl(execl_path_name, CHILDETCONE, i, NULL);)。发出信号后,父母等待所有孩子完成任务。

我很了解处理程序功能,但在这些方面我不清楚:

  1. 我需要在处理程序函数中插入我的execl吗?

  2. 从答案到上一个问题,我不明白最后一个循环的重要性:

    for (int i = 0; i < NUMBER_TRAINS; i++)
           {
               wait(NULL);
           }
    

这是我的代码:

#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include "accessory.h"


#define NUMBER_TRACKS 16
#define NUMBER_STATIONS 8
#define NUMBER_TRAINS 5

#define TRACKS_INITIALS "MA"
#define STATION_INITIALS "S"
#define SIZE 256
#define CHILDETCONE "childETCone"

void handler(int sig);

int main(int argc , char *argv[]) {
    pid_t pid;
    pid_t pid_array[NUMBER_TRAINS];

    char track_name[2];
    char track_number[2];
    int execl_return;
    char str[2];
    char * execl_path_name;

    memset(pid_array, 0, sizeof(pid_array));

    /* create the MAx file initialized to zero */
    for (int i = 1; i < (NUMBER_TRACKS + 1); i++) {
        memset(track_name, '\0', sizeof(track_name));
        memset(track_number, '\0', sizeof(track_number));
        strcpy(track_name, TRACKS_INITIALS);
        sprintf(track_number, "%d", i);
        strcat(track_name, track_number);
        create_track_file(track_name, "", SIZE);
    }

    execl_path_name = get_file_name(CHILDETCONE, "", SIZE);
    printf("path %p\n", execl_path_name);


    for(int i = 0; i < NUMBER_TRAINS; i++) {
        pid = fork();

        if (pid < 0) {
            perror("fork");
            exit(1);
        }
        if (pid == 0) { //child
            //sprintf(str, "%d", i+1);
            //execl_return = execl(execl_path_name, CHILDETCONE, i, NULL);
            signal(SIGUSR1, handler);
            pause();
            exit(0);
        }
        //parent
        pid_array[i] = pid;
    }

    for (int j = 0; j < NUMBER_TRAINS; j++) {
        kill(pid_array[j], SIGUSR1);
        sleep(1);
    }

    for (int i = 0; i < NUMBER_TRAINS; i++) {
        wait(NULL);
    }

    return 0;
}

void handler(int sig) {
    printf("printed from child [%d]\n", getpid());
    printf("signal [%d]\n", sig);
}

1 个答案:

答案 0 :(得分:1)

  

我需要在处理程序函数中插入我的execl吗?

不。 pause()仅在被调用的过程捕获到导致信号处理功能运行的信号后才返回。因此,execl调用可以在pause调用之后进行。我认为您的情况会更清楚。

也请注意,POSIX标准化了一系列“异步信号安全”功能,这些功能对于信号处理程序可以安全地调用,而对于 un 而言,处理程序可以安全地调用其他功能。 execl在列表中,但printf和其他流I / O功能不是。信号处理程序不应调用printf。您特定的信号处理程序根本不需要执行任何操作。

另外,考虑使用sigsuspend()代替pause(),因为前者可以让您更好地控制哪些信号导致火车发动。

  

我不从答案中理解最后一个循环的意义   上一个问题:

for (int i = 0; i < NUMBER_TRAINS; i++)
       {
           wait(NULL);
       }

wait()函数指示调用过程阻塞,直到其子级之一终止。循环进行与子级一样多的wait()调用,因此在没有错误的情况下,主程序直到其所有子级都终止后才继续执行。

您似乎可能已经尝试通过使用sleep()循环在循环中调用kill来达到类似的目的,但是这种策略是完全错误的。首先, 在每个kill之后等待,意味着孩子的execl通话将至少间隔sleep时间,这不是我想要的。第二,您无法提前知道孩子们需要多长时间才能完成,因此在某些情况下,您允许的一秒钟可能不够。第三,由于您似乎希望孩子们很快跑起来,所以一秒钟可能比您大多数时候需要的时间要多得多。

相关问题