Search code examples
cmultithreadingpthreadssignalsterminate

Proper multi-thread program termination. C


Hi I'm stuck with this problem and I can't figure out which is the best solution for that:

I have a process with some threads. All the threads have signal masked and only one (SignalHandler) that check if there are pending signals.

  while(!shouldEnd){
        if(!sigwait(&set, &signum)){
            if(signum == SIGINT){
                fprintf(stderr, "Ricevuto SIGINT\n");
            }
            else{
                //TODO
            }
        }
    }

Now I would like to terminate even other threads when it receive a SIGINT (for instance). How can I do it properly ? The main problem is that the others thread might be waiting on a condition variable or waiting in a accept() (for socket connections). I think would be a good thing put a variable like "shouldEnd" and set it to 1 when threads should stop working. Is that a good idea ? And what about the waiting one ? Mostly for the one waiting for a socket connection ?


Solution

  • So, first and foremost, we don't know what you're using for threads. You might consider using libBoost for this, as it will make your life easier with RAII style locks and whatnot.

    Anyhow, only the elected thread of your process (typically main(), in most examples), will catch the signal, unless you've enabled signal masking. When you want the threads to shut down cleanly, you just need to:

    1. Wakeup the threads waiting on accept() by modifying your FD set to include a pipe that can also wake up the blocking call.
    2. Simply signal the condvars the other threads are waiting on, and set some sort of mutex-protected boolean/flag to notify the thread that it should exit early (ie: mutexLock()l; bool bExitEarly = true; signal(condVar); mutexUnlock();).
    3. Assuming you spawned the threads as joinable (ie: non-detached), just make sure you have a copy of the pointer to each thread object, and call thread_join() on each of them after you've signaled them to stop. This will ensure that the threads are fully stopped before main() exits. If you don't do this, main() could exit before the threads are done, and just forcibly kill off the threads while they are in the middle of their shutdown logic, which is messy, and could cause your program to crash or worse.