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

标签 c macos pthreads

我发现两个线程之间使用 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

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

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

最佳答案

我添加:

void dummy(int sig) {
    dprintf(1, "Dummy %d\n", sig);
}

和:

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

靠近主线顶部;它按预期工作,并且永远不会调用dummy。 在man sigwait中:

The signals specified by set should be blocked, but not ignored, at the time of the call to sigwait().

更新:如果将其更改为 fork 到 thr_fn 而不是 pthread_create,则无需建立虚拟参数即可工作;这导致了一个假设:macos 在创建线程时欺骗了 SIG_DFL。 这与 pthreads+signal 的困惑状态并不矛盾。如果您计划使用这两种范例,您可能需要暂停......

关于c - sigwait 在 MacOS 上复制和转换信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63730499/

相关文章:

c - WINDOWS 上的 OpenSSL!! - ld.exe 找不到 -lcrypto/-leay32

c - MIT OpenCourseWARE C/C++ 作业 1 无输出问题

python - TLS MAC 消息验证

c - 是否应该从 main() 返回或调用 exit() 禁用线程取消?

c - 将 CURL 结果放入字符串而不是 STDOUT?

我们可以在不知道其类型的情况下取消引用 void 指针吗?

c++ - 使用 MetroWerks C/C++ 开发的 C/C++ 资源

python - PyInstaller 图标选项在 Mac 上不起作用

c - pthread_kill 不会杀死线程 C linux

c++ - 以编程方式获取与 htop 的相应 pid 匹配的进程的线程 Id