2017-05-23 52 views
0

我有一个父进程,它在循环中使用fork创建了16个子进程。最终,每个孩子都会发送一个SIGUSR1信号,该信号由父进程中的处理函数处理。C - 多个孩子 - 信号互相覆盖

我的问题是这样的 - 有些孩子发送的信号,而来自另一个孩子的信号处理。我读到处理函数然后停止并处理新信号,忽略它正在处理的当前信号。

我试图通过在处理函数的开始处发送:kill(0,SIGSTOP)来解决此问题,但看起来像停止父进程一样。有没有办法将这个信号发送给孩子?

如果不可能,我的目标是否可以使用wait, waitpid and kill实现?

添加下面的代码,我离开了东西一样检查读取的返回值,开放等

处理函数:

void my_signal_handler(int signum, siginfo_t* info, void* ptr) 
{ 
    kill(0, SIGSTOP); 
    int sonPid = info->si_pid; 
    char* pipeName = malloc(14 + sizeof(int));//TODO ok? 
    sprintf(pipeName, "//tmp//counter_%d" , (int) sonPid); //TODO double //? 
    size_t fdPipe = open(pipeName, O_RDONLY); 
    int cRead; 
    int countRead = read(fdPipe,&cRead,sizeof(int)); 
    COUNT+= cRead; 
    kill(0, SIGCONT); 
    return; 
} 

创建子进程:

struct sigaction new_action; 
memset(&new_action, 0, sizeof(new_action)); 
new_action.sa_handler = my_signal_handler; 
new_action.sa_flags = SA_SIGINFO; 
if(0 != sigaction(SIGUSR1, &new_action, NULL)) 
{ 
    printf("Signal handle registration failed. %s\n", strerror(errno)); 
    return -1; 
} 
for(int i=0; i<16; i++){ 
    pid_t cpid = fork(); 
    if(cpid == 0) // child 
    { 
     execv("./counter",argvv); // some arguments to the function 
     printf("execv failed: %s\n", strerror(errno)); 
     return -1; 
    } 
    else{ 
     continue; 
    } 

儿童的计数器程序,总之它计数字符counc在文件的某些部分的外观,然后打印到一个管道:

int main(int argc, char** argv){ 
    int counter = 0; 
    char counc = argv[1][0]; 
    char* filename = argv[2]; 
    off_t offset = atoll(argv[3]); 
    ssize_t length = atoll(argv[4]); 
    int fd = open(filename, O_RDWR | O_CREAT); 
    char* arr = (char*)mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); 
    for(int i=0; i<length; i++){ 
     if(arr[i] == counc){ 
      counter++; 
     } 
    } 
    pid_t proid = getpid(); 
    pid_t ppid = getppid(); 
    char* pipeName = malloc(14 + sizeof(pid_t)); 
    sprintf(pipeName, "//tmp//counter_%d" , (int) proid); 
    size_t fdPipe = mkfifo(pipeName, 0777); 
    int didopen = open(pipeName,O_WRONLY); 
    size_t wrote = write(fdPipe,&counter , 1); 
    if(wrote < 0){ 
     printf(OP_ERR, strerror(errno)); 
     return errno; 
    } 
    kill(ppid, SIGUSR1); 
//close the pipe and unmap the array 
return 1; 
} 
+0

请将您的代码作为正确的[最小,完整和可验证示例](https://stackoverflow.com/help/mcve)(请仔细阅读该页面)。 – Arash

+0

我认为在这种情况下可以解释一下,但我会尽快添加一个代码示例。 – Gray

+0

这是不正确的,被处理的信号被阻塞直到处理程序完成,所以如果它们都发送相同的信号,你应该没问题。一些代码将有助于识别您的**真实**问题。顺便说一句,保持处理程序简短,只需设置标志并在信号处理程序外执行复杂的处理。 –

回答

0

如果我正确理解你的问题,你有困难在父亲和孩子分别期望的信号功能。如果这不是你的情况,请纠正我。

如果您的问题是这样,您可以简单地创建一些if语句,以测试fork()调用返回的pid,然后只有在您是父亲时才执行。所以......

if (pid == 0) 
      //ChildProcess(); 
      // do nothing! 
    else 
      //ParentProcess(); 
      // do something! 

请注意,您必须定义size_t pid作为一个全局变量,可见在这两个主要和信号处理函数要实现!

+0

它不是 - 问题是父进程有16个孩子,当他处理来自孩子1的信号时,孩子2发送一个新信号,导致孩子的信号1没有正确处理。 – Gray

+0

然后,你只需要预先定义哪个PID引用了什么孩子,并创建这样的'if'语句。 – Diaman

0

除了其他人已经指出的有关在信号处理程序中使用非异步安全功能的情况,我要出去解决问题,并猜测问题是以下两种情况之一:

  1. 您错误地认为通过kill发送的信号排队等待发送给它们的进程。他们没有排队(除非你在支持它的操作系统上使用sigqueue);目标进程的一组待处理(但未处理)的信号被更新。见signal queuing in C。或者,
  2. 您在不支持“可靠信号语义”的操作系统上运行此代码。见man 3 sysv_signal为洞察(恐怖)像:

然而sysv_signal()提供系统V不可靠信号的语义,即:a)所述信号的配置被复位为当调用处理程序的默认值; b)在信号处理程序正在执行时,信号的进一步实例未被阻塞;