tags:

views:

129

answers:

3

Hi,

I have a pthread waiting on a condition variable using pthread_cond_wait. It's waiting for data from a queue structure that is filled by another thread. I want to kill this thread, preferably without pthread_kill. On Linux and WinPthreads doing a pthread_cancel(); pthread_join() is enough to kill it. However, on OS X it hangs on the pthread_join call. Any suggestions?

A: 

The first thing I would try would be to kick the condition variable in between the cancel and the join, and have your target thread check for cancellation explicitly after it returns from the condition wait.

That's because it may be that the thread is not responding to cancellation while it's in the condition wait (or at all).

POSIX.1c-2004 (v6) states:

The cancelability state and type of any newly created threads, including the thread in which main() was first invoked, shall be PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DEFERRED respectively.

That means you have to explicitly check for cancellation with pthread_testcancel().

The other option is to actually set the threads cancel type to PTHREAD_CANCEL_ASYNCHRONOUS when it first starts to run, something like:

int junk;
pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &junk);
std::cout
    << ((junk==PTHREAD_CANCEL_DEFERRED) ? "Was deferred" : "Wasn't")
    << std::endl;

That is, of course, assuming that's what the problem is. You should be able to test if it is by examining the output of that third line above.

Cancellation is a request to the target thread which it is free to ignore if it wishes, as opposed to the far more evil pthread_kill(). I'm a great believer in letting threads control their own lifetimes since I've found it invariably leads to fewer concurrency problems.

Aside: In fact, having been bought up in very early editions of pthreads, even before integration into DCE, I still find myself just using a global variable for each thread indicating when it should exit, along with manually kicking mutexes or condition variables to wake the threads up. I guess I should update my methods (or I would if I could see a clear advantage). :-)

paxdiablo
Well, I would definitely prefer to have some non-cancel method but I have but the thread that gets cancel isn't actually aware that it's running in a thread.I have tried signalling the condition variable, but it then reads from the queue and segfaults because there is nothing in it. While this has the desired behavior of exiting the program, it seems 'just wrong.'
CarbonAsh
BTW, you should never assume that, just because you return from cond_wait, there is work available. It's possible for two threads waiting to be woken, the first to get the work and the second should detect no work available and go back to wait.
paxdiablo
+1  A: 

pthread_cancel should wake a thread that is blocked in pthread_cond_wait --- this is one of the required cancellation points. If it doesn't work then something is wrong.

The first thing to check is that cancellation is indeed enabled on the target thread --- explicitly call pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,&oldstate) on the target thread to make sure. If that doesn't work, then cancellation is broken on your platform and you'll have to resort to alternatives such as setting a "please stop now" flag and signalling the condition variable.

Do not use asynchronous cancellation unless you really know what you are doing --- it can trigger the cancellation in the middle of any operation (e.g. in the middle of setting up a function call stack frame or running a destructor), and thus can leave your code in a thoroughly inconsistent state. Writing async-cancel-safe code is hard.

Incidentally pthread_kill does not kill a thread --- it sends a signal to it.

Anthony Williams
CarbonAsh
pthreads works fine, I wrote a little program:pthread_cond_t cond;pthread_mutex_t lock;void* tmain(void *){ pthread_mutex_lock( pthread_cond_wait( pthread_mutex_unlock(}int main(){ pthread_t thread; pthread_cond_init( pthread_mutex_init( pthread_create( sleep(1); pthread_cancel(thread); pthread_join(thread, NULL);}To test it and it exits after a second. I must have some other bug in my code.
CarbonAsh
+3  A: 

Do you have access to the queue, and control of the object schema for enqueued items? If so, define a queue object type that when de-queued, instructs the thread that is processing the item to exit gracefully.

Now, to shut down these threads, simply post a number of these "quit" objects to the HEAD of the queue that corresponds to the number of threads that are servicing the queue, and join on the threads.

This seems much cleaner than the "nuclear option" of pthread_cancel/kill.

Bukes
This is actually exactly what I did! Thanks for the suggestion, this way my thread can still remain in the dark and run in non threaded instances and my queue which is already thread aware can take care of the dirty work and call pthread_exit to kill the thread.
CarbonAsh