我正在将多线程应用程序从HP-UX迁移到Solaris,到目前为止,除了一件事之外一切正常!应用程序有一个处理信号的线程,当收到其中一些信号时,它运行一些清理(记录,杀死子进程等)。
我尽可能地减少了代码,使得一个显示问题的简单示例成为可能:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <synch.h>
#include <iostream>
#include <unistd.h>
using namespace std;
pthread_t m_signalHandlerThread;
sigset_t m_signalSet;
void signalHandler()
{
while ( true )
{
cout << "SigWait..." << endl;
sigwait( &m_signalSet, &sig );
cout << "Signal!! : " << sig << endl;
break;
}
cout << "OUT" << endl;
}
void* signalHandlerThreadFunction( void* arg )
{
signalHandler();
return (void*)0;
}
int main()
{
sigemptyset( &m_signalSet );
sigaddset( &m_signalSet, SIGQUIT ); //kill -QUIT
sigaddset( &m_signalSet, SIGTERM ); //kill
sigaddset( &m_signalSet, SIGINT ); //ctrl-C
sigaddset( &m_signalSet, SIGHUP ); //reload config
if ( pthread_create( &m_signalHandlerThread, NULL, signalHandlerThreadFunction, NULL ) )
{
cout << "cannot create signal handler thread, system shut down.\n" << endl;
}
int iTimeout = 0;
while (1)
{
if (iTimeout >= 10)
break;
sleep(1);
iTimeout++;
cout << "Waiting... " << iTimeout << endl;
}
cout << "END" << endl;
exit (0);
}
使用编译命令行: 的Solaris:
CC -m64 -g temp.cpp -D_POSIX_PTHREAD_SEMANTICS -lpthread
HP-UX:
/opt/aCC/bin/aCC +p +DA2.0W -AA -g -z -lpthread -mt -I/usr/include temp.cpp
运行两个应用程序,行为(在10秒循环中按CTRL + C):
HP-UX:
./a.out
SigWait...
Waiting... 1
Waiting... 2
Signal!! : 2 <---- CTRL + C
OUT
Waiting... 3
Waiting... 4 <---- CTRL + C again to terminate
的Solaris:
./a.out
SigWait...
Waiting... 1
Waiting... 2 <---- CTRL + C
^C
任何帮助都会受到欢迎,因为我已经撕裂了我的头发(不多了):)!
谢谢!
答案 0 :(得分:4)
未指定哪两个线程将处理SIGINT。如果只需要一个线程来处理信号,则需要在所有其他线程中阻止该信号。
答案 1 :(得分:1)
您应该使用pthread_sigmask
阻止信号到其他线程。该页面还包含一个带有信号处理线程的程序示例。
答案 2 :(得分:1)
关于如何在多线程应用程序中很好地处理信号的唯一方法是执行以下操作:
main()
在生成任何其他线程之前,尽早阻止pthread_sigmask()
中的所有信号。sigwait()
或sigwaitinfo()
以简单的循环处理信号。这样,除了专用于信号处理的线程之外的任何线程都不会获得信号。此外,由于信号传递是同步的,因此您可以使用任何线程间通信工具,这与经典信号处理程序不同。
答案 3 :(得分:-1)
这是处理信号的非正统方式。如果你想结合信号和线程,更好的选择是将信号在内部序列化的通常signal handlers转换为负责实际处理事件的另一个线程。
这也是一个更好的选择,因为未定义MT应用程序中的哪个线程接收信号。任何没有阻塞信号的线程都可能收到它。如果您有2个线程(并且示例中有两个线程),那么任何线程都可能获得SIGINT。
您可能需要检查sigprocmask()
,以告诉操作系统应该在线程中阻止SIGINT。对于每个线程,IIRC甚至是那个调用sigwait()
的线程都应该这样做。
Edit1。实际上我错误地认为“应该为每个线程完成”。新线程从当前线程继承其信号掩码。我已经意识到这不可能是真的,因为那会引入竞争条件:信号到达新线程创建但尚未设置其信号掩码的时间。换句话说,在主线程中设置信号掩码就足够了。