【发布时间】:2020-09-03 19:32:51
【问题描述】:
我看到使用 posix pthread/signaling 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 Checker\n");
while(1) {
err = sigwait(&mask, &signo);
if (err != 0)
{
printf("sigwait failed %d\n",err);
exit(1);
}
switch(signo)
{
case SIGUSR1:
printf("SIGUSR1\n");
break;
case SIGUSR2:
printf("SIGUSR2\n");
break;
case SIGABRT:
printf("SIGABRT\n");
break;
default:
printf("Signal %d\n",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 %d\n",x);
usleep(100000);
// raise(SIGUSR1);
pthread_kill(tid, SIGUSR1);
pthread_kill(tid, SIGUSR2);
pthread_kill(tid, SIGABRT);
usleep(500000);
printf("\n");
}
printf("Done\n");
exit(0);
}
我希望看到 5 组已识别的信号,如下所示:
set 1
SIGUSR1
SIGUSR2
SIGABRT
我希望每个信号都有 1 个代表,但我认为期望信号井然有序是不合理的。
$ 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
请注意,set 1 中有 2 个 SIGUSR2。每次我运行程序时,我经常会发出不同数量的信号。使用注释掉的 raise(SIGUSR1) 代替 pthread_kill(tid,SIGUSR1) 没有帮助。
那么问题是 SIGWAIT 发生了什么?为什么信号可以改变类型,或者在信号队列中重复。为什么这是不一致的行为?我们看到这项工作在 Linux 中 100% 有效,但在 WSL 中也表现不佳。
【问题讨论】:
-
我在运行 Mojave 并使用 clang 版本 11.0.0 编译的 MacOS 上对其进行了测试,实际上我在第一组中得到了 Signal 0,我还看到重复的 SIGUSR1 但 SIGABRT 似乎工作得相当一致 - 很奇怪.
-
我想知道 OS X 线程是否像旧的 LinuxThreads 实现那样使用 SIGUSRn 信号?
-
我们在第一组中也看到了信号 0。这很奇怪,因为它不在 SIGxxx 列表中。