【问题标题】:How to sync two process (child and parent) with signals in C?如何将两个进程(子进程和父进程)与 C 中的信号同步?
【发布时间】:2018-06-28 03:53:49
【问题描述】:

我想使用信号 (SIGUSR1) 来同步 C 中的进程。我希望父进程等待一个信号,当接收到这个信号时,将相同的信号发送给子进程。我写了一小段来激发推理,但它并没有消失。

#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>



void trataSIGUSR1(int sigNum) {
    printf("SIGUSR1\n");
}

int main(void) {

    pid_t pid;
    struct sigaction sa;

    pid = fork();

    if (pid == 0) {
        struct sigaction sa = {0};
        sa.sa_handler = trataSIGUSR1;
        sa.sa_flags = 0;
        sigemptyset(&sa.sa_mask);
        sigaction(SIGUSR1,&sa,NULL);
        pause();
        printf("This never execute");
    } else {
        printf("I'am father: %d!\n",getppid());
        kill(0,SIGUSR1);
        pause();
    }
}

输出

I'am father: 12082!
User defined signal 1: 30

【问题讨论】:

  • 也许尝试在父级中等待信号,然后尝试向父级发送信号。
  • 我该怎么做?我不知道如何等待信号,我不想使用忙等待。
  • 你能告诉我如何使用它吗?我可以设置一个特定的信号以在pause()之后继续代码?
  • 试试sigaction() - examine and change a signal action。如需更多详细信息,只需输入man sigaction

标签: c process signals


【解决方案1】:

简单的提示是使用pause()kill(),即pause()用于阻止进程执行,直到收到任何信号,一旦收到信号,然后do_something()kill()用于发送SIGUSR1信号。

此外,当您使用pause() 时,它会暂停进程,直到收到任何信号,并且对于该信号,默认操作应该是用户定义的 ISR。来自pause()的手册页

返回值 pause() 仅在 signal was caughtsignal-catching function 返回时返回。 在这种情况下 pause() 返回 -1,并且 errno 设置为 EINTR。

这里是示例所需的示例代码

//int nSIGINT = 0; /* declare variable of type volatile sigatomic_t  */
volatile sigatomic_t nSIGINT;
void trataSIGINT(int sigNum) {
    nSIGINT = 1;/* set the flag as needed */
}
int main(void ){
        int pid;
        pid=fork();/* create child process */
        if(pid==0) {    
                //signal(SIGUSR1,trataSIGINT);/* instead of signal() use sigaction  */
                struct sigaction sa = {0}; /* initialize sa or fill all its members*/
                sa.sa_handler = trataSIGINT;/* set the handler to trataSIGINT*/
                sa.sa_flags = 0;
                sigemptyset(&sa.sa_mask);
                sigaction(SIGUSR1,&sa,NULL); /* when child received SIGUSR1, trataSIGINT gets called */
                pause(); /* wait until any signal received */
                /* do_something_child() code, this you want to run only after receiving signal */

        }
        else { 
                /* do_something_parent() */
                printf("parent about to send user signal to child\n");
                kill(pid,SIGUSR1); /*send SIGUSR1 to child */
                wait(0); /* wait till child completes  */
        }
        return 0;
}

旁注,用于在收到SIGUSR1 时在trataSIGINT() 中设置标志,而不是将int nSIGINT = 0; 声明标志变量的类型为volatile sigatomic_t 类型。

来自 ISO/IEC 9899:2011 §7.14.1.1 signal 函数

¶5 如果信号不是由于调用abortraise 函数,如果信号处理程序的行为未定义 指具有static 或线程存储持续时间的任何对象 不是lock-free atomic object,而是将值分配给 声明为volatile sig_atomic_t 的对象或信号处理程序 调用标准库中除abort 之外的任何函数 函数、_Exit 函数、quick_exit 函数或 第一个参数等于信号编号的信号函数 对应于导致处理程序调用的信号。 此外,如果对信号函数的这种调用导致 SIG_ERR 返回,errno 的值是不确定的。252)

252) 如果任何信号由异步信号处理程序生成,则 行为是undefined

【讨论】:

  • 请注意,pause() 返回 i 收到任何信号。您可能希望将其放入一个检查 volatile int usr1_received; 的循环中,并在 SIGUSR1 的信号处理程序中将其设置为 true。并避免任何已经使用 SIGUSR1 本身的库。最好使用 posix 互斥锁和条件。
  • yes true @GoswinvonBrederlow 或 volatile sigatomic_t usr1_received; 会更好,因为 sigatomic_t 类型总是以原子方式访问并避免中断访问变量的不确定性。
  • kill(0,SIGUSR1); 是什么?应该是kill(pid,SIGUSR1);
  • 为什么pause() 在父进程中?删除它,在kill 之后。
  • 请说明投反对票的原因。
猜你喜欢
  • 1970-01-01
  • 2016-07-31
  • 1970-01-01
  • 2019-06-17
  • 1970-01-01
  • 2019-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多