簡體   English   中英

在C中的父子進程之間傳遞信號

[英]Passing signals between parent and child process in C

我正在嘗試使用信號在父進程和子進程之間傳遞,但是例如在我的示例中打印出前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;
}

預先感謝您的幫助!

我只是參考這些功能的文檔-我沒有使用它們的經驗。

看來sigfillset()要做的是將過程信號掩碼加載到您的sigset_t 這意味着您的sigset_t將包含當前進程阻止的信號集。 我假設默認值是什么都不會被阻止,因此該設置將為空。

您可能希望通過打印出集合的內容或僅在調試器中對其進行測試來進行測試。

現在從文檔中我了解了sigdelset(&p_myset, SIGUSR1)作用是從剛剛填充的集合中刪除信號SIGUSR1 假設此集合已經為空,因此此調用不太可能執行任何操作。 再次,通過在調試器中查看進行驗證。

因此,現在sigsuspend()要做的是用新的掩碼替換您的過程信號掩碼,假定與默認掩碼沒有什么不同(同樣, 請在調試器中進行檢查 )。 然后在子端將等待,直到進程接收到SIGUSR1並通過信號處理程序對其進行處理。 因此,您的孩子將處理SIGUSR1但這僅僅是因為這是默認行為。

您的示例代碼似乎未安裝任何信號處理程序。 我認為您必須調用sigaction()函數來執行此操作。 因此,默認信號處理程序很有可能會運行以處理SIGUSR1

根據此頁面SIGUSR1的默認信號處理為

(i)...該過程異常終止。 該過程因_exit()的所有后果而終止,除了用於wait()和waitpid()的狀態指示通過指定信號異常終止。

所以我猜想孩子在父母kill(child_pid, SIGUSR1)時就死了。 這將意味着孩子不會在身邊向父母發信號。

這主要是我的猜測。 我為您推薦的是學習如何使用gdb或其他調試器,以便您可以設置一些斷點並逐步了解程序的實際作用。

在父級和子級都定義了struct sigaction sigaction之后,您忘記了調用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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM