Почему использование pthread_mutex_lock и pthread_cond_wait внутри обработчика сигналов приводит к пропущенным сигналам?Linux

Ответить
Anonymous
 Почему использование pthread_mutex_lock и pthread_cond_wait внутри обработчика сигналов приводит к пропущенным сигналам?

Сообщение Anonymous »

Я столкнулся с состоянием гонки или потенциальной взаимоблокировкой при использовании примитивов синхронизации pthreads внутри обработчика сигналов. Моя цель состоит в том, чтобы получить сам сигнал потока, а затем заставить обработчик сигнала ждать, пока условие будет выполнено другим потоком.
Настройка:
Поток A: отправляет сигнал самому себе.
Обработчик сигнала потока A: ожидание pthread_cond
Поток B: отправка сигнала.

Код: Выделить всё

#define _GNU_SOURCE
#include
#include 
#include 
#include 
#include 
#include 
#include 

static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  cond  = PTHREAD_COND_INITIALIZER;

static int flag = 1;
static pthread_t thread_a_tid;

/* -------- Signal handler (INTENTIONALLY BROKEN) -------- */
static void signal_handler(int signo, siginfo_t *info, void *ucontext)
{
int sts;

/* busy-trylock (already illegal in signal handler) */
do {
sts = pthread_mutex_trylock(&mutex);
} while (sts == EBUSY);

while (flag) {
/* Artificial delay to widen race window */
for (volatile unsigned i = 0; i < 100000; ++i) {
__asm__ __volatile__("" ::: "memory");
}

/* ❌ NOT async-signal-safe */
pthread_cond_wait(&cond, &mutex);
}

pthread_mutex_unlock(&mutex);
}

/* -------- Thread A -------- */
static void *thread_a(void *arg)
{
/* Install signal handler */
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = signal_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);

if (sigaction(SIGRTMIN + 2, &sa, NULL) != 0) {
perror("sigaction");
exit(1);
}

thread_a_tid = pthread_self();

while (1) {
/* do some job */
usleep(1000);

/* send signal to self */
flag = 1;
pthread_kill(thread_a_tid, SIGRTMIN + 2);
}

return NULL;
}

/* -------- Thread B -------- */
static void *thread_b(void *arg)
{
while (1) {
/* simulate poll() */
usleep(5000);

/* do some job */

/* wake up thread A */
pthread_mutex_lock(&mutex);
flag = 0;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}

return NULL;
}

int main(void)
{
pthread_t ta, tb;

if (pthread_create(&ta, NULL, thread_a, NULL) != 0 ||
pthread_create(&tb, NULL, thread_b, NULL) != 0) {
perror("pthread_create");
return 1;
}

pthread_join(ta, NULL);
pthread_join(tb, NULL);
return 0;
}
Проблема: Иногда сигналы кажутся «потерянными». Что еще более важно, если я добавлю фиктивную задержку (длинный пустой цикл) между блокировкой мьютекса и вызовом wait в обработчике сигнала, проблема будет возникать гораздо чаще. Такое ощущение, что мьютекс не обеспечивает ожидаемой атомарности или изоляции.
Вопросы:
Я знаю, что использование pthread_mutex и pthread_cond внутри обработчика сигнала принципиально небезопасно; это не вопрос.
Я пытаюсь понять, может ли это реально объяснить поведение, которое я наблюдаю (например, мьютекс, который работает неправильно, или сигналы, которые кажутся пропущенными), и какой внутренний механизм вызывает такие сбои.
Примечательно, что когда я избегаю обработчика сигналов и выполняю ту же логику непосредственно из потока (что возможно в моем случае), проблема до сих пор не воспроизводится. Я хотел бы понять, является ли это принципиально правильным решением или оно просто маскирует другую основную проблему.

Подробнее здесь: https://stackoverflow.com/questions/798 ... handler-ca
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Linux»