【问题标题】:sigwait duplicated and transformed signals on MacOSsigwait 在 MacOS 上复制和转换信号
【发布时间】: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 列表中。

标签: c macos pthreads


【解决方案1】:

我补充说:

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

和:

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

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

set 指定的信号应该被阻塞,但不能被忽略,在 这 sigwait() 的调用时间。

update: 如果你把它fork 改成 thr_fn 而不是 pthread_create,它可以在不建立虚拟参数的情况下工作;这导致了一个假设:macos 在创建线程时欺骗了 SIG_DFL。 这与 pthreads+signals 的混乱情况并不矛盾。如果您打算同时使用这两种范例,您可能需要点击暂停....

【讨论】:

  • 我会试试这个。需要明确的是,根据手册页,注册信号处理程序可确保信号不会被忽略?我们正在使用信号和 pthread 来编写 RTOS 仿真。这与 pthreads 映射得很好,与 fork 有很大不同。
  • 我能够添加一个信号处理程序,然后阻止所有信号。 sigwait 仍然偶尔会产生奇怪的结果。
  • 我在 main 开头附近使用了信号,如您所示,而不是 sigaction,它似乎工作正常。
【解决方案2】:

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

【讨论】:

  • 遗憾的是,我们在终端上进行了测试,发现行为不正确。
猜你喜欢
  • 1970-01-01
  • 2020-03-09
  • 2020-03-21
  • 1970-01-01
  • 2021-09-04
  • 1970-01-01
  • 2016-09-14
  • 1970-01-01
  • 2015-04-12
相关资源
最近更新 更多