
On Wed, Oct 03, 2007 at 07:47:57PM -0400, Scott Gifford wrote:
As with most Unix servers, the server is shut down with an OS signal telling the server to shut down. The server catches this signal, then simply calls exit(1). Any important cleanup happens in the destructors of global variables, so it will happen properly no matter how the server exits.
This is not "properly"; I guessed your problem upfront before I had finished reading this very paragraph :) First, you need to block SIGINT in all threads except the main thread. If you don't have a main thread, make it just for the purpose of signal handling. Otherwise, SIGINT will be delivered to a random thread. Maybe that's OK in your case. Second, you don't need to lock the mutex before signaling the condition variable (this is what causes your deadlock). Third, how do you clean up threads which are NOT waiting at the condition variable at the moment of signal arrival? Fourth, your cleanup is NOT "proper" in any way because your cleanup executes in the context of signal handler. In that context (i.e. before the signal handler returns - which is never in your case), only async-signal safe functions may be used. Neither mutex locking nor condition signal is async signal safe. So how do you do it "properly." Hm: have another, 'main' thread just for the purposes of signal handling; have SIGINT unblocked in this thread and block it in all other threads. That thread does something like: while(!flag) sigsuspend(...); and SIGINT just sets the flag to true. When the while() loop exits, you're out of the signal context and then you may use functions such as pthread_cancel() to cancel all threads, or pthread_kill() to explicitly deliver signal to all threads and yes, also pthread_cond_signal() and pthread_cond_broadcast(). Then use pthread_join() to wait that all threads finish and _then_ call exit from the main thread. (If you use pthread_kill, you have the same caveat with async signal safe functions). I'm not sure that even the above scheme is 100% fool-proof, but it seems less broken than your current solution. Also, I don't see how you can use them to notify threads that also do some work outside of their monitor, i.e. if they are structured like: while(1) { // get mutex // wait on condition // do some work // release mutex // do some more work (*) } If you signal the variable while the thread is executing in (*), it will never pick up the signal. How do you do it in Boost.Thread - I don't know. The whole idea of using destructors to clean up global data in a multi-threaded program sounds like calling for trouble. While the destructors themselves may use locks, in how many threads is the destructor list walked and cleaned (the code generated by the compiler to walk over the list of global objects and call destructor for each) executing? Does your runtime library and/or compiler guarantee that every global destructor is executed exactly once even in a MT setting? (This sounds kinda the inverse of the threadsafe singleton pattern.)
Does anybody have any suggestions for a straightforward way to handle this properly?
Um, signals and threads don't mix well. No "straightforward" solution. Read about and understand async-signal safety.