更新:这似乎是一个时间问题。在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 Receivedn");
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 threadn");
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: %dn", (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=%dn", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %dn", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %dn", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continuedn");
}
exit(EXIT_SUCCESS);
}
生成以下输出:
My pid: 14101, child_tid: 14102
killed by signal 10
子进程显然是被信号杀死的,为什么没有调用信号处理程序?
为了避免竞争条件,在clone()
调用之前在父进程上捕获信号。子进程继承父进程的信号处理程序的副本。如果需要,您可以稍后在父节点上将其重置为SIG_DFL。(此外,getpid()
是异步信号安全的,如果你想在父级上模拟SIG_DFL行为)。
子进程没有收到信号,因为在子进程到达sigaction
调用之前,父进程正在发送信号,这就是为什么它被杀死了。您应该避免这样设置信号处理程序。但是,如果你想这样做,那么确保父进程等待子进程设置信号处理程序。在这个场景中,您应该看到预期的结果。
首先奇怪的是你没有收到这个消息:
"Hello from cloned threadn"
因此,你的子进程在它设法设置信号处理程序之前被终止。
编辑:我刚刚看到你关于睡眠的评论。尝试添加另一个变量,该变量在执行sigaction
时设置。主线程应该被阻塞,直到这个变量没有被设置。