HP-UX 和 Solaris 10 之间的 POSIX 线程行为不同
我正在将多线程应用程序从 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
任何帮助都会更受欢迎,因为我已经撕破了头发(剩下的不多了) ):)!
谢谢!
I'm migrating a multi threaded application from HP-UX to Solaris and so far, everything is OK except for one thing! The application has a thread that is handling the signals and, when some of them are received, it runs some cleaning (logging, kill child processes and so on).
I've reduced the code as much as it was possible to make a somehow simple example showing the problem:
#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);
}
Using compile command lines:
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
Running both applications, the behaviour (pressing CTRL+C while in the 10 seconds loop):
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
Any help will be more then welcome since I'm already tearing my hair (not much left) :)!
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
未指定 2 个线程中的哪一个将处理 SIGINT。如果您只需要一个线程来处理该信号,则需要在所有其他线程中阻止该信号。
It's unspecified which of your 2 threads will handle SIGINT. If you need only one of your threads to handle the signal, you need to block that signal in all the other threads you have.
您应该使用
pthread_sigmask
。该页面还包含带有信号处理线程的程序示例。You should block signals to other threads by using
pthread_sigmask
. that page also contains an example for a program with a signal handling thread.在多线程应用程序中处理好信号的唯一方法是执行以下操作:
sigwait()
或sigwaitinfo()
在简单循环中处理信号。这样,除了专用于信号处理的线程之外,没有任何线程可以获得信号。此外,由于信号传递是以这种方式同步的,因此您可以使用您拥有的任何线程间通信设施,这与经典信号处理程序内部不同。
About the only way how to handle signals well in multithreaded application is to do the following:
main()
early, before any other threads are spawned, usingpthread_sigmask()
.sigwait()
orsigwaitinfo()
to handle the signals in a simple loop.This way no threads except the one dedicated for signal handling will get the signals. Also, since the signal delivery is synchronous this way, you can use any inter-thread communication facilities you have, unlike inside classic signal handlers.
这是处理信号的相当非正统的方式。如果您想将信号和线程结合起来,更好的选择是使用通常的 信号处理程序,信号在内部序列化到另一个负责实际处理事件的线程。
这也是一个更好的选择,因为 MT 应用程序中的哪个线程接收信号是未定义的。任何没有阻止该信号的线程都可能会收到它。如果您有 2 个线程(并且示例中有两个线程),则任何线程都可能收到 SIGINT。
您可能需要检查
sigprocmask()
作为告诉操作系统 SIGINT 应该在线程中阻塞的一种方式。这应该对每个线程执行,IIRC 甚至是调用 sigwait() 的线程。编辑1。实际上,我对上面的“应该为每个线程完成”的看法是错误的。新线程从当前线程继承其信号掩码。我意识到这不可能是真的,因为这会引入竞争条件:信号在新线程创建但尚未设置其信号掩码时到达。也就是说,在主线程中设置信号掩码就足够了。
This is rather unorthodox way to handle signals. If you want to marry the signals and threads, better choice would be to have the usual signal handlers from where the signal is serialized internally to another thread which is responsible for the actual handling of the event.
That is also a better option, as it is undefined which thread in an MT application receives the signal. Any threads which doesn't have the signal blocked might receive it. If you have 2 threads (and you have two threads in the example) then any of the threads might get the SIGINT.
You might want to check
sigprocmask()
as a way to tell OS that SIGINT should be blocked in a thread. That should be done for every thread, IIRC even the one callingsigwait()
.Edit1. Actually I'm wrong about the "should be done for every thread" bit above. A new thread inherits its signal mask from the current thread. I have realized that that can't be true because that would have introduced the race condition: signal arrives at the time when new thread created but hasn't yet set its signal mask. In other words, it is sufficient to set the signal mask in the main thread.