c-sigwait在MacOS上复制和转换信号



我看到使用posix pthread/信令api的两个线程之间的信令不一致。

这是我的测试程序

#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *thr_fn(void *arg)
{
int err, signo;
sigset_t    mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
sigaddset(&mask,SIGUSR2);
sigaddset(&mask,SIGABRT);
printf("Thread Checkern");

while(1) {
err = sigwait(&mask, &signo);
if (err != 0)
{
printf("sigwait failed %dn",err);
exit(1);
}

switch(signo)
{
case SIGUSR1:
printf("SIGUSR1n");
break;
case SIGUSR2:
printf("SIGUSR2n");
break;
case SIGABRT:
printf("SIGABRTn");
break;
default:
printf("Signal %dn",signo);
break;
}
}
}
int main(void)
{
int         err;
pthread_t   tid;
sigset_t mask;

sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
sigaddset(&mask,SIGUSR2);
sigaddset(&mask,SIGABRT);
pthread_sigmask(SIG_BLOCK,&mask,NULL);

err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)
{
printf("can't create thread %d",err);
exit(1);
}
sleep(1);
for(int x=0;x<5;x++)
{
printf("set %dn",x);
usleep(100000);
// raise(SIGUSR1);
pthread_kill(tid, SIGUSR1);
pthread_kill(tid, SIGUSR2);
pthread_kill(tid, SIGABRT);
usleep(500000);
printf("n");
}

printf("Donen");
exit(0);    
}

我希望看到的是5组识别信号,类似于以下:

set 1
SIGUSR1
SIGUSR2
SIGABRT

我希望每个信号都有一个代表,但我认为期望信号有序是不合理的。

$ cc -pthread main.c
$ ./a.out
Thread Checker
set 0
SIGUSR1
SIGABRT
SIGUSR2
set 1
SIGUSR2
SIGABRT
SIGUSR2
set 2
SIGUSR1
SIGABRT
SIGUSR2
set 3
SIGUSR1
SIGABRT
SIGUSR2
set 4
SIGUSR1
SIGABRT
SIGUSR2
Done
Program ended with exit code: 0

注意,集合1中有2个SIGUSR2。每次运行程序时,我经常会收到不同数量的信号。使用注释掉的raise(SIGUSR1(代替pthread_kill(tid,SIGUSR1。

所以问题是SIGWAIT发生了什么?为什么信号可以更改类型,或者在信号队列中重复。为什么这种行为不一致?我们看到这在Linux中100%有效,但在WSL中也表现不佳。

我添加了:

void dummy(int sig) {
dprintf(1, "Dummy %dn", sig);
}

和:

signal(SIGUSR1, dummy);
signal(SIGUSR2, dummy);
signal(SIGABRT, dummy);

主管道顶部附近;它按预期工作,并且从不调用dumm。在man sigwait中:

set指定的信号应在这个调用sigwait((的时间。

update:如果将其更改为fork为thr_fn而不是pthread_create,则它可以在不建立伪参数的情况下工作;这导致了一个hyphoguess:macos在创建线程时忽略了SIG_DFL。这与pthread+信号的混乱并不矛盾。如果你打算同时使用这两种范式,你可能需要点击暂停。。。。

我的最佳猜测是,当您观察到奇怪的行为时,您正在macOS上的调试器下运行程序。尝试在没有调试器的情况下直接从终端运行它。

最新更新