#c #macos #pthreads
#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(amp;mask);
sigaddset(amp;mask,SIGUSR1);
sigaddset(amp;mask,SIGUSR2);
sigaddset(amp;mask,SIGABRT);
printf("Thread Checkern");
while(1) {
err = sigwait(amp;mask, amp;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(amp;mask);
sigaddset(amp;mask,SIGUSR1);
sigaddset(amp;mask,SIGUSR2);
sigaddset(amp;mask,SIGABRT);
pthread_sigmask(SIG_BLOCK,amp;mask,NULL);
err = pthread_create(amp;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
Я ожидаю увидеть 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? Почему возможно, чтобы сигналы меняли тип или дублировались в очереди сигналов. Почему это не согласованное поведение? Мы видим, что это работает на 100% в Linux, но в WSL это также плохо работает.
Комментарии:
1. Я протестировал это на своем macOS, работающем под управлением Mojave и компилирующемся с clang версии 11.0.0, и я действительно получил сигнал 0 в первом наборе там, я также вижу дублирующийся SIGUSR1, но SIGABRT, похоже, работает довольно стабильно — странно.
2. Интересно, используют ли потоки OS X сигналы SIGUSRn для вещей, подобных старой реализации LinuxThreads?
3. Мы также видели сигнал 0 в первом наборе. Это очень странно, поскольку его нет в списке SIGxxx.
Ответ №1:
Я добавил:
void dummy(int sig) {
dprintf(1, "Dummy %dn", sig);
}
и:
signal(SIGUSR1, dummy);
signal(SIGUSR2, dummy);
signal(SIGABRT, dummy);
в верхней части main; и это работает так, как ожидалось, и фиктивный никогда не вызывается.
В man sigwait:
Сигналы, указанные set, должны блокироваться, но не игнорироваться, во время вызова sigwait().
обновление: если вы измените это на fork в thr_fn вместо pthread_create , это будет работать без установления фиктивных параметров; что приводит к гипотезе: macos изменяет SIG_DFL при создании потока. Это не противоречит беспорядку, который представляют собой сигналы pthreads . Если вы планируете использовать обе эти парадигмы, возможно, вам захочется нажать паузу….
Комментарии:
1. Я попробую это сделать. Для ясности, регистрация обработчика сигнала гарантирует, что сигнал не игнорируется на странице руководства? Мы используем сигналы и pthreads для написания симуляции RTOS. Это несколько хорошо сочетается с pthreads и сильно отличается от fork.
2. Я смог добавить обработчик сигналов, а затем заблокировать все сигналы. Sigwait по-прежнему иногда выдает странные результаты.
3. Я использовал signal в начале main, как вы показываете, вместо sigaction, и, похоже, он работает правильно.
Ответ №2:
Я предполагаю, что вы запускаете программу в debugger на macOS, когда наблюдаете странное поведение. Попробуйте запустить его непосредственно с терминала без отладчика.
Комментарии:
1. К сожалению, мы протестировали на терминале и увидели неправильное поведение.