在C中传递父进程和子进程之间的信号

时间:2014-06-16 18:41:26

标签: c unix

我正在尝试使用信号在父进程和子进程之间传递,但是在打印前2个语句之后 例如,在我的节目中显示:

儿童4225:跑步,父母是4224

父母4224:告诉孩子进程4225开始

它永远陷入困境!我不知道我在哪里出错...

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
void p_sig_usr(int signo){
    if(signo == SIGUSR1){
        printf("*** Parent SIGUSR1 handler - Received 'task started' signal from child        ***\n");
    }
    if(signo == SIGUSR2){
        printf("*** Parent SIGUSR2 handler - Received 'task completed' signal from child ***\n");
    }
    else
        printf("unexpected signal received");
    return;
}
void c_sig_usr(int signo){
    if(signo == SIGUSR1){
        printf("*** Child SIGUSR1 handler - Received 'task start' signal from parent ***\n");
    }
    if(signo == SIGUSR2){
        printf("*** Child SIGUSR2 handler - Received 'task complete verification' signal from parent ***\n");
    }
    else
        printf("unexpected signal received");
    return;
}

int main(void)
{
    pid_t child_pid, parent_pid;
    parent_pid = getpid();
    struct sigaction p_sig;
    sigemptyset(&p_sig.sa_mask);
    p_sig.sa_flags = 0;
    p_sig.sa_handler = p_sig_usr;
    child_pid = fork();
    if ( child_pid == -1){
        perror("failed to fork a new process");
        return 1;
    }
    if (child_pid == 0){
        struct sigaction c_sig;
        sigset_t c_myset;
        sigemptyset(&c_sig.sa_mask);
        c_sig.sa_flags = 0;
        c_sig.sa_handler = c_sig_usr;
        child_pid = getpid();
        printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
        sigfillset(&c_myset);
        sigdelset(&c_myset, SIGUSR1);
        sigsuspend(&c_myset);//suspend until get SIGUSR1
        printf("CHILD: Telling parent that I'm starting task.\n");
        sleep(3);
        kill(parent_pid, SIGUSR1);
        printf("CHILD: Performing task\n");
        sigfillset(&c_myset);
        sigdelset(&c_myset, SIGUSR2);
        sigsuspend(&c_myset);//suspend and wait for SIGUSR2
        printf("CHILD: Telling parent that work is done.\n");
        kill(parent_pid, SIGUSR2);
        printf("CHILD %d: Finished\n", child_pid);
    }
    else{
        struct sigaction p_sig;
        sigset_t p_myset;
        sigemptyset(&p_myset);
        sleep(3);//parent now sleeping to let child set up handlers
        printf("PARENT %d: Telling the Child Process %d to start\n", parent_pid, child_pid);
        kill(child_pid, SIGUSR1);
        sigfillset(&p_myset);
        sigdelset(&p_myset, SIGUSR1);
        sigsuspend(&p_myset);//suspend until get SIGUSR1
        sleep(3);
        kill(child_pid,SIGUSR2);
        printf("PARENT: Told child to notify of task completion.\n");
        sigfillset(&p_myset);
        sigdelset(&p_myset, SIGUSR2);//suspend until get SIGUSR2
        printf("PARENT %d: Finished.", parent_pid);
    }
    return 0;
}

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

我只是提到这些功能的文档 - 我没有使用它们的经验。

sigfillset()似乎要将process signal mask加载到sigset_t。这意味着您的sigset_t将包含您的流程当前阻止的信号集。我假设默认情况下没有被阻止,因此该集合将为空。

您可能希望通过打印出该组的内容来测试它,或者只是在调试器中查看它。

现在从文档中我了解sigdelset(&p_myset, SIGUSR1)将会做什么从您刚刚填充的集合中移除信号SIGUSR1。假设这个集合已经是空的,所以这个调用不太可能做任何事情。再次,通过在调试器中查看它来验证。

所以现在sigsuspend()要做的是用你的新掩码替换你的进程信号掩码,假设与默认掩码没有任何不同(再次,在调试器中检查< /强>)。然后在子端将等待进程收到SIGUSR1并通过信号处理程序处理它。因此,您的孩子将处理SIGUSR1,但这只是因为这是默认行为。

您的示例代码似乎没有安装任何信号处理程序。我想你必须调用sigaction()函数来做到这一点。因此,默认信号处理程序很可能会运行以处理SIGUSR1

根据this pageSIGUSR1的默认信号处理是

  

(i)......异常终止该过程。该过程终止于_exit()的所有后果,除了wait()和waitpid()可用的状态指示指定信号的异常终止。

所以我猜父母做kill(child_pid, SIGUSR1)时孩子就死了。这意味着孩子不在身边向父母发出信号。

这主要是我的猜测。我建议您学习如何使用gdb或其他一些调试器,这样您就可以设置一些断点并逐步了解程序实际执行的操作。

答案 1 :(得分:0)

在父母和孩子之间定义sigaction后,您忘了拨打struct sigaction。另外,请注意在父进程中重新定义struct sigaction p_sig

所以,我想如果你把你的程序改成下面列出的那样,它应该可以工作。

--- foo.c   2014-06-16 16:37:10.918932118 -0300
+++ bar.c   2014-06-16 16:37:48.710228467 -0300
@@ -36,10 +36,6 @@
 {
     pid_t child_pid, parent_pid;
     parent_pid = getpid();
-    struct sigaction p_sig;
-    sigemptyset(&p_sig.sa_mask);
-    p_sig.sa_flags = 0;
-    p_sig.sa_handler = p_sig_usr;
     child_pid = fork();
     if ( child_pid == -1){
         perror("failed to fork a new process");
@@ -51,6 +47,7 @@
         sigemptyset(&c_sig.sa_mask);
         c_sig.sa_flags = 0;
         c_sig.sa_handler = c_sig_usr;
+        sigaction(SIGUSR1, &c_sig, NULL);
         child_pid = getpid();
         printf("CHILD %d: Running, parent is %d\n",child_pid, parent_pid);
         sigfillset(&c_myset);
@@ -69,6 +66,10 @@
     }
     else{
         struct sigaction p_sig;
+        sigemptyset(&p_sig.sa_mask);
+        p_sig.sa_flags = 0;
+        p_sig.sa_handler = p_sig_usr;
+        sigaction(SIGUSR1, &p_sig, NULL);
         sigset_t p_myset;
         sigemptyset(&p_myset);
         sleep(3);//parent now sleeping to let child set up handlers