Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ruby-on-rails-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 我的POSIX信号处理器中的竞争条件_C_Posix_Signals_Race Condition_Waitpid - Fatal编程技术网

C 我的POSIX信号处理器中的竞争条件

C 我的POSIX信号处理器中的竞争条件,c,posix,signals,race-condition,waitpid,C,Posix,Signals,Race Condition,Waitpid,下面的程序派生出一个反复运行“/bin/sleep 10”的子程序。父级为SIGINT安装一个信号处理程序,将SIGINT传递给子级。但是,有时向子级发送SIGINT失败。为什么会这样?我错过了什么 #include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wa

下面的程序派生出一个反复运行“/bin/sleep 10”的子程序。父级为SIGINT安装一个信号处理程序,将SIGINT传递给子级。但是,有时向子级发送SIGINT失败。为什么会这样?我错过了什么

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

pid_t foreground_pid = 0;

void sigint_handler(int sig)
{
    printf("sigint_handler: Sending SIGINT to process %d\n",
            foreground_pid);

    if ((foreground_pid != 0) && kill(foreground_pid, SIGCONT) == -1) {
        perror("sending SIGINT to forground process failed");
        printf("foreground_pid == %d", foreground_pid);
        exit(EXIT_FAILURE);
    }

    foreground_pid = 0;
}

int main(int argc, const char *argv[])
{
    while (1) {
        pid_t child_pid;

        if ((child_pid = fork()) == -1) {
            perror("fork failed");
            exit(EXIT_FAILURE);
        }

        if (child_pid) { /* parent */
            foreground_pid = child_pid;

            printf("waiting for child (%d) to complete ...\n", child_pid);
            fflush(stdout);

            /* install SIGINT signal handler */
            struct sigaction sa;
            struct sigaction old_handler;
            sa.sa_handler = sigint_handler;
            sigemptyset(&sa.sa_mask);
            sa.sa_flags = SA_RESTART | SA_RESETHAND;
            sigaction(SIGINT, &sa, NULL);

            int status = 0;

            /* wait for child to finish */
            if (waitpid(child_pid, &status, 0) == -1) {
                perror("waitpid failed");
                exit(EXIT_FAILURE);
            }

            printf("    done.\n");
            fflush(stdout);

        }
        else { /* child */
            char * const argv[] = { "/bin/sleep", "10", NULL};

            if (execve(argv[0], argv, NULL) == -1) {
                perror("execve failed");
                exit(EXIT_FAILURE);
            }

            exit(EXIT_SUCCESS);
        }

    }

    return EXIT_SUCCESS;
}

% make && ./foo
gcc -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L foo.c -o foo
waiting for child (4582) to complete ...
^Csigint_handler: Sending SIGINT to process 4582
    done.
waiting for child (4583) to complete ...
^Csigint_handler: Sending SIGINT to process 4583
sending SIGINT to forground process failed: No such process
foreground_pid == 4583
#包括
#包括
#包括
#包括
#包括
#包括
#包括
pid\u t前台\u pid=0;
无效sigint_处理程序(int sig)
{
printf(“sigint\u处理程序:将sigint发送到进程%d\n”,
前景(pid),;
if((前景pid!=0)和&kill(前景pid,SIGCONT)=-1){
perror(“将SIGINT发送到放弃进程失败”);
printf(“前景pid==%d”,前景pid);
退出(退出失败);
}
前景_pid=0;
}
int main(int argc,const char*argv[]
{
而(1){
pid_t child_pid;
if((child_pid=fork())==-1){
perror(“fork失败”);
退出(退出失败);
}
if(child_pid){/*parent*/
前景_pid=子_pid;
printf(“正在等待子项(%d)完成…\n”,子项ID);
fflush(stdout);
/*安装SIGINT信号处理程序*/
struct-sigaction-sa;
struct sigaction old_处理程序;
sa.sa_handler=sigint_handler;
sigemptyset(和sa.sa_面具);
sa.sa_flags=sa_重启| sa_重置手;
sigation(SIGINT,&sa,NULL);
int status=0;
/*等孩子说完*/
if(waitpid(子pid和状态,0)=-1){
perror(“waitpid失败”);
退出(退出失败);
}
printf(“完成。\n”);
fflush(stdout);
}
else{/*儿童*/
char*const argv[]={“/bin/sleep”,“10”,NULL};
if(execve(argv[0],argv,NULL)=-1){
perror(“Exeve失败”);
退出(退出失败);
}
退出(退出成功);
}
}
返回退出成功;
}
%制作&&。/foo
gcc-Wall-pedantic-std=c99-D_POSIX_C_SOURCE=200809L foo.C-o foo
正在等待孩子(4582)完成。。。
^Csigint_处理程序:将SIGINT发送到进程4582
完成。
正在等待孩子(4583)完成。。。
^Csigint_处理程序:将SIGINT发送到进程4583
向forground进程发送SIGINT失败:没有此类进程
前景_pid==4583

当您键入Ctrl+C时,tty驱动程序对整个进程组执行一个
SIGINT
;这包括子进程,该子进程将作为响应退出,因为它没有安装处理程序。所以你在重复已经做过的事情,以及当父母试图
kill()
杀死孩子时,孩子是否还在身边,这有点像废话。

没错。在我看来,一个解决方案是在fork之后在子进程中调用setId(),将子进程放入新的会话和组中,这应该可以防止SIGINT信号到达子进程。@SlappyTheFish:
setpgrp()
setpgid()
在这种情况下是首选的,但我怀疑正确的答案只是让tty驱动程序来处理它。此外,还可以在子级(fork和execve之间)安装SIG_IGN as信号处理程序。@geekosaur我检查了文档,但我不能100%确定为什么在这种情况下setgrp()比setid()更可取。这是因为不一定要创建新会话?@SlappyTheFish:事实上,在这种情况下没有太大的实际区别;同一会话中的单独进程组可以连接到终端,也可以与终端分离(这就是
fg
的工作原理)。这更多的是无关流程与相关但不应附加到tty的流程之间的概念差异。