分叉和信号在C



谁能帮我一步通过下面的C代码来理解输出应该是什么?

int x = 0;
pid_t pid;
int flag=1;
void handler1(int sig) {
    x=x+1;
    printf("%dn",x);
    fflush(stdout);
    exit(0);
}
void handler2(int sig) {
    x = x + 2;
    flag = 0;
    waitpid(-1,NULL, 0);
}
int main() {
    signal(SIGUSR1, handler1);
    signal(SIGCHLD, handler2);
    printf("%dn",x);
    fflush(stdout);
    if ((pid = fork()) == 0) {
        while(1) {};
    }
    kill(pid, SIGUSR1);
    while(flag) {};
    printf("%dn",x);
    fflush(stdout);
    exit(0);
}

我认为输出应该是"213",但我不确定。

从技术上讲,它是未定义的,因为您使用来自信号处理程序的stdio函数。我会用单个write替换printf/fflush组合(但实际冲洗流的奖励点)。退出信号处理程序也被认为是不好的形式。

同时,xflag都需要变成volatile

    发生的第一件事是打印x,而它的值仍然是0
  1. 则进程为fork() ed。
  2. SIGUSR1传递给子进程,并在其中调用处理程序。处理程序在子对象中增加x,并打印1
  3. 子进程退出,父进程的SIGCHLD处理程序被调用,父进程的x副本(仍然为0)增加2。
  4. 父进程退出循环轮询flag,并打印当前值2

所以输出应该是012

这段代码是一个父线程'main()'和一个由'fork()'创建的子线程的故事。

故事从父线程开始,它用信号处理程序设置舞台,然后打印出x的值,该值先前被初始化为0

然后,父线程生成"子"线程,向子线程发送SIGUSR1信号,然后陷入while循环。跳出循环的唯一方法是清除父元素的副本。"国旗"变量。

现在故事转向了孩子;事实证明,子进程能够继承父进程的所有财富,包括它自己的'x'副本(由父进程初始化为0)。

不幸的是,在出生后,孩子进入了一个无限循环。子进程退出循环的唯一方法是处理一个"信号"。幸运的是,对于孩子来说,父母碰巧做到了。如前面所述,父进程在父进程陷入循环之前已经向子进程发送了SIGUSR1信号。

因此,子线程冲到'handler1()',(父线程先前指定为'SIGUSR1'处理程序)。在那里,它将其(子线程)的'x'副本从0增加到1,并打印新值(1)。打印后,子线程被'exit()'函数简单地终止。

…但这孩子的故事还不止这些!当孩子咽下最后一口气时,它会向父进程发出一个'SIGCHLD'信号(多亏了'exit()'函数)。然后,孩子被放置到最后的休息。(安息吧,孩子,安息吧)

同时,父进程被困在循环中;但是'SIGCHLD'信号导致父进程运行到'handler2()',(父进程先前指定为'SIGCHLD'处理程序)。在处理程序中,父节点首先将'x'的副本从0更改为2。但你猜家长发现了什么?导致父进程陷入循环的"标志"。因此,父进程清除标志,这将(在从'handler2()'返回循环后)将父进程从循环中释放出来。

然而,在离开'handler2()'之前,父线程做最后一次检查,以确保丢失已久的'子'线程已死。当发现是这种情况时,父进程悲伤地返回到它被限制的循环中。

重新进入循环时,父进程发现标志已清除,并跳出循环!然后输出它的'x'副本(2),然后终止它自己。

#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
int x = 0;
pid_t pid;
int flag=1;
/* SIGUSR1 Signal Handler. */
/* Executed by child thread when parent sends a 'SIGUSR1' signal to child. */
void handler1(int sig)
   {
   /* Change the child's copy of 'x' from 0 to 1. */   
   x=x+1;
   /* Print the value of x [1]. 'flush()' ensures that it prints -now- */
   printf("%dn",x);
   fflush(stdout);
   /* A 'SIGCHLD' signal is sent to the parent, and thread self-terminates. */
   exit(0);
   }
/* SIGCHLD Signal Handler. */
/* Executed by the parent (main) thread when child sends a 'SIGCHLD' signal to parent. */
void handler2(int sig)
   {
   /* Parent changes it's copy of 'x' from 0 to 2 */
   x = x + 2;
   /* Clear 'flag', allowing parent 'main()' thread to break out of 'while()' loop. */
   flag = 0;
   /* Wait for all child processes to terminate. */
   waitpid(-1,NULL, 0);
   }
int main()
  {
  /* Register 'handler1()' as the 'SIGUSR1' signal handler. */   
  signal(SIGUSR1, handler1);
  /* Register 'handler1()' as the 'SIGCHLD' signal handler. */
  signal(SIGCHLD, handler2);
  /* Print the value of x [0]. 'flush()' ensures that it prints -now- */
  printf("%dn",x);
  fflush(stdout);
  /* 'fork()' creates a 'child' process. */ 
  if ((pid = fork()) == 0)
     {
     /* This "infanate loop" is executed by the 'child' process only. */
     while(1)
        {};
     }
  /* Parent 'main()' thread sends a 'SIGUSR1' signal to the 'child' process. */   
  kill(pid, SIGUSR1);
  /* Loop, waiting for child to clear 'flag' */
  while(flag)
     {};
  /* Print the value of x [2]. 'flush()' ensures that it prints -now- */
  printf("%dn",x);
  fflush(stdout);
  /* Terminate parent 'main()' thread. */
  exit(0);
  }
输出:

0
1
2

最新更新