Обработка сигналов в pthreads - PullRequest
22 голосов
/ 12 марта 2011

Я создал pthread и установил обработчик сигнала внутри него, так же, как мы делаем в функции main( ).Обработчик сигнала потока является отдельной функцией.Удивительно, но он не работает, то есть обработчик сигналов потока не может перехватывать сигналы.

Вот код:

#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>

typedef struct data
{
 char name[10];
 int age;
}data;

void sig_func(int sig)
{
 printf("Caught signal: %d\n",sig);
 signal(SIGSEGV,sig_func);
}

void func(data *p)
{
 printf("This is from thread function\n");
 signal(SIGSEGV,sig_func); // Register signal handler inside thread
 strcpy(p->name,"Mr. Linux");
 p->age=30;
 sleep(2); // Sleep to catch the signal
}

int main()
{
 pthread_t tid;
 pthread_attr_t attr;
 data *ptr;

 pthread_attr_init(&attr);
 pthread_create(&tid,&attr,(void*)func,ptr);
 pthread_kill(tid,SIGSEGV);

 pthread_join(tid,NULL);
 printf("Name:%s\n",ptr->name);
 printf("Age:%d\n",ptr->age);
}

Вывод:

Ошибка сегментации (что означает, что обработчик не улавливает сигнал)

Ответы [ 3 ]

26 голосов
/ 12 марта 2011

Есть несколько проблем с вашим кодом:

  • ptr не инициализирован, поэтому все части ptr-> вылетят из программы
  • , которую вы вызываете pthread_kill()немедленно, очень вероятно, до того, как обработчик сигнала был установлен, и в потоке (который имеет неопределенное поведение)
  • вы вызываете printf() из обработчика сигнала, который не гарантированно работает (см. man 7 signal длясписок безопасных функций)

Это будет работать намного лучше, хотя вам все равно потребуется правильная синхронизация потоков, и, как указано в другом месте, вы должны использовать sigaction():

#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>

typedef struct data
{
 char name[10];
 int age;
}data;

void sig_func(int sig)
{
 write(1, "Caught signal 11\n", 17);
 signal(SIGSEGV,sig_func);
}

void func(data *p)
{
 fprintf(stderr, "This is from thread function\n");
 strcpy(p->name,"Mr. Linux");
 p->age=30;
 sleep(2); // Sleep to catch the signal
}

int main()
{
 pthread_t tid;
 pthread_attr_t attr;
 data d;
 data *ptr = &d;

 signal(SIGSEGV,sig_func); // Register signal handler before going multithread
 pthread_attr_init(&attr);
 pthread_create(&tid,&attr,(void*)func,ptr);
 sleep(1); // Leave time for initialisation
 pthread_kill(tid,SIGSEGV);

 pthread_join(tid,NULL);
 fprintf(stderr, "Name:%s\n",ptr->name);
 fprintf(stderr, "Age:%d\n",ptr->age);
}

Редактировать : установить sighandler в основной поток

10 голосов
/ 12 марта 2011

Я считаю, что суть проблемы заключается в том, что сигналы доставляются процессу в целом, а не отдельным потокам.Обычно один поток назначается для обработки всех сигналов;все остальные потоки (включая основной поток) должны блокировать сигналы, используя pthread_sigmask().

. Вы можете установить маску, чтобы блокировать все сигналы, запустить поток обработчика сигналов, снять маскусигналы, которые вы хотите обработать, а затем вернитесь в основной поток, запустите все остальные потоки, которые вам нужны.Они будут наследовать маску «блокировать все сигналы» от основного потока.

Кстати, пришло время отойти от signal(3) и переключиться на sigaction(2), который имеет надежную семантику и лучше стандартизирован.(И, следовательно, более портативным.)

4 голосов
/ 12 марта 2011

Одна проблема с вашим кодом, о которой еще никто не упомянул, заключается в том, что, хотя блокировка сигнала (и доставка, если вы используете pthread_kill или raise) для каждого потока, обработчики сигналов для каждого процесса.Это означает, что они являются очень плохим механизмом для взаимодействия между потоками, особенно если ваш код когда-либо будет использоваться в качестве библиотечного кода, поскольку для библиотеки крайне плохое поведение изменять обработчики сигналов вызывающей стороны.

Также обратите вниманиечто использование обработчиков сигналов для связи между потоками имеет неоптимальную производительность по сравнению с другими методами сигнализации потоков, такими как условные переменные или барьеры, поскольку существует по крайней мере один дополнительный переход пользователь-ядро-пользователь (когда возвращается обработчик сигнала).

...