HP-UX 和 Solaris 10 之间的 POSIX 线程行为不同

发布于 2024-09-28 10:21:43 字数 2293 浏览 8 评论 0原文

我正在将多线程应用程序从 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

怪异←思 2024-10-05 10:21:43

未指定 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.

乖不如嘢 2024-10-05 10:21:43

您应该使用 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.

很酷又爱笑 2024-10-05 10:21:43

在多线程应用程序中处理好信号的唯一方法是执行以下操作:

  1. 在生成任何其他线程之前,使用 pthread_sigmask() 尽早阻止 main() 中的所有信号代码>.
  2. 生成一个信号处理线程。使用 sigwait()sigwaitinfo() 在简单循环中处理信号。

这样,除了专用于信号处理的线程之外,没有任何线程可以获得信号。此外,由于信号传递是以这种方式同步的,因此您可以使用您拥有的任何线程间通信设施,这与经典信号处理程序内部不同。

About the only way how to handle signals well in multithreaded application is to do the following:

  1. Block all signals in main() early, before any other threads are spawned, using pthread_sigmask().
  2. Spawn a signals handling thread. Use sigwait() or sigwaitinfo() 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.

雾里花 2024-10-05 10:21:43

这是处理信号的相当非正统的方式。如果您想将信号和线程结合起来,更好的选择是使用通常的 信号处理程序,信号在内部序列化到另一个负责实际处理事件的线程。

这也是一个更好的选择,因为 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 calling sigwait().


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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文