sigwait在MacOS上复制和转换了信号

问题描述

我发现两个线程之间使用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。每次我运行程序时,我都会频繁发出不同数量的信号。使用注释掉的抬高(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 中:

set所指定的信号应该在 的 调用sigwait()的时间。

更新:如果将其从 fork 更改为thr_fn而不是pthread_create,则它无需建立虚拟参数即可工作;这就导致了猜测:macos在创建线程时欺骗了SIG_DFL。 这与pthreads + signals的混乱并不一致。如果您打算同时使用这两种范例,则可能需要暂停....

,

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