c++ – POSIX Threads behaviour different between HP-UX and Solaris 10 – Education Career Blog

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!

,

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.

,

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.

,

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.

,

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.

Leave a Comment