web-dev-qa-db-ja.com

pthreadでの信号処理

main( )関数で行うのと同じ方法で、pthreadを作成し、その中にシグナルハンドラーをインストールしました。スレッドのシグナルハンドラは独立した関数です。驚くことに、それは機能していません。つまり、スレッドのシグナルハンドラはシグナルをキャッチできません。

コードは次のとおりです。

#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);
}

出力:

セグメンテーション違反(シグナルがハンドラーによってキャッチされないことを意味します)

22
kingsmasher1

コードにはいくつかの問題があります。

  • 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をインストールします

26
sam hocevar

問題の核心は、個々のスレッドではなく、プロセス全体にシグナルが配信されることだと思います。通常、すべての信号を処理するために単一のスレッドが指定されます。他のすべてのスレッド(メインスレッドを含む)は pthread_sigmask()を使用してシグナルをブロックする にする必要があります。

マスクを設定して、すべてのシグナルをブロックし、シグナルハンドラースレッドを開始し、処理するシグナルのマスクを解除し、メインスレッドに戻って、必要な他のすべてのスレッドを開始できます。メインスレッドから「すべての信号をブロック」マスクを継承します。

ちなみに、signal(3)から離れて、sigaction(2)に切り替える時間です。これは、信頼できるセマンティクスを持ち、より標準化されています。 (したがって、よりポータブルです。)

10
sarnold

誰もまだ言及していないコードの問題の1つは、信号のブロック(および配信、pthread_killまたはraise)はスレッドごと、シグナルハンドラはプロセスごとです。これは、ライブラリが呼び出し側のシグナルハンドラを変更することは非常に悪い動作であるため、特にコードがライブラリコードとして使用される場合、スレッド間通信の非常に悪いメカニズムであることを意味します。

また、スレッド間の通信にシグナルハンドラを使用すると、条件変数やバリアなどの他のスレッドシグナル方式と比較してパフォーマンスが最適化されないことに注意してください。

4
R..