C 在克隆线程上发送和处理信号

C 在克隆线程上发送和处理信号,c,signals,signal-handling,C,Signals,Signal Handling,更新:这似乎是一个时间问题。在调用kill之前添加一个sleep调用可以使一切按预期工作 我一直在玩克隆(2),并试图弄清楚它是如何工作的。我目前无法向克隆进程发送信号。我有以下代码: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <signal.h> #include <sched.h> #include <sys/types.h>

更新:这似乎是一个时间问题。在调用kill之前添加一个sleep调用可以使一切按预期工作

我一直在玩克隆(2),并试图弄清楚它是如何工作的。我目前无法向克隆进程发送信号。我有以下代码:

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

volatile int keep_going = 1;

typedef void (*sighandler_t)(int);

void handler(int sig) {
   printf("Signal Received\n");
   keep_going = 0;
}

int thread_main(void* arg) {
   struct sigaction usr_action;
   sigset_t block_mask;
   sigfillset(&block_mask);
   usr_action.sa_handler = &handler;
   usr_action.sa_mask = block_mask;
   usr_action.sa_flags = 0;
   sigaction(SIGUSR1, &usr_action, NULL);
   printf("Hello from cloned thread\n");
   while(keep_going);
}

int main(int argc, char **argv) {
   void* stack = malloc(4096);
   int flags = SIGCHLD;
   int child_tid = clone(&thread_main, stack + 4096, flags, NULL);
   if (child_tid < 0) {
      perror("clone");
      exit(EXIT_FAILURE);
   }
   printf("My pid: %d, child_tid: %d\n", (int) getpid(), (int) child_tid);
   int kill_ret = kill(child_tid, SIGUSR1);
   if (kill_ret < 0) {
      perror("kill");
      exit(EXIT_FAILURE);
   }
   int status = 0;
   pid_t returned_pid = waitpid(child_tid, &status, 0);
   if (returned_pid < 0) {
      perror("waitpid");
      exit(EXIT_FAILURE);
   }
   if (WIFEXITED(status)) {
      printf("exited, status=%d\n", WEXITSTATUS(status));
   } else if (WIFSIGNALED(status)) {
      printf("killed by signal %d\n", WTERMSIG(status));
   } else if (WIFSTOPPED(status)) {
      printf("stopped by signal %d\n", WSTOPSIG(status));
   } else if (WIFCONTINUED(status)) {
      printf("continued\n");
   }
   exit(EXIT_SUCCESS);
}

孩子显然是因为信号而被杀的,为什么信号处理程序没有被调用?

首先奇怪的是你没有收到这个消息:

"Hello from cloned thread\n"
因此,您的子线程在设置信号处理程序之前会被终止

编辑:
我刚看到你关于睡眠的评论。尝试添加另一个变量,该变量在执行
sigaction
时设置。在未设置此变量之前,应阻止主线程。

为避免争用情况,请在调用
clone()
之前捕获父线程上的信号。子级继承父级信号处理程序的副本。如果需要,可以稍后在父级上将其重置为SIG_DFL。(另外,
getpid()
是异步信号安全的,如果您想在父级上模拟SIG_DFL行为)。

子级没有收到信号,因为在子级调用
sigaction
之前,父级正在发送信号,这就是它被杀死的原因。您应该避免这样设置信号处理程序。但是,如果您只想这样做,请确保父级正在等待,直到子级设置信号处理程序。在这个场景中,您应该会看到预期的结果。

如果我在kill调用之前添加一个sleep调用,它就会起作用。看起来这是一个时间问题。问题:既然我已经解决了问题,而且不一定有答案,那么程序是什么?我应该编辑我的问题并以某种方式关闭它,还是创建我自己的答案并给它“接受的答案”?如果我在杀死之前添加一个睡眠呼叫(睡眠10秒),我会得到:我的pid:14164,child_tid:14165 Hello from cloned thread Signal Received exited,status=10,那么,在前面的场景中,子线程的信号处理程序尚未安装。为了使它在实际应用中更加健壮,当初始化完成时,子代会向父代发出信号,然后父代可以继续。我喜欢这样。在反复阅读了克隆人(2)主页几个小时后,它有这么多的意义,太可惜了,我没有早点弄明白:)嗨,阿米特。欢迎来到这个网站!我编辑了一下,使你的英语更地道一点。好的洞察力!
"Hello from cloned thread\n"