views:

359

answers:

3

How can I interrupt a sleeping/blocked boost::thread?

I am using Boost v1.33.1, upgrading is not an option.

Thank you.

A: 

There is no way to interrupt blocked thread in boost::thread. You need to implement proper thread interruption yourself, using boost::conditional for example.

AFAIK Any existing ways to interrupt running thread (TerminateThread in Windows API for example) only lead to problems (memory leaks one of them).

begray
+1  A: 

A quick perusal of the documentation for boost.thread in 1.33 suggests that there is no portable way to achieve interruption. Thread interruption was introduced (for threads in one of the boost "interruption points") in 1.35.

As a result the only option I can think of is to use signals (which aren't in 1.33 either, so you'll need to fall back on, for example, pthreads) combined with time-outs on any methods that are blocking. Basically use signals to wake threads that are asleep by having them sleep waiting for the signal and timeouts on blocking threads to have them wake up and check to see if they should exit. Unfortunately this is a highly undesirable solution, and to some extent amounts to what newer versions of boost do internally anyway.

If you're using boost.thread, then you should consider upgrading to a more recent version for other projects because 1.33 doesn't support the vast majority of constructs that are essential for multi-threading.

Adam Bowen
A: 

I agree with begray, look into condition variables. If you have threads you want to wake up from time to time, they are what boost expects you to use. If you expect that threads are going to block on other calls (like calls into BSD sockets or something similar) this doesn't help you. You will need to use the timeout facilities of those calls directly, if they exist.

Here's an example, using only facilities available in boost 1.33.1. I haven't compiled it, so there may be small errors. I've included the use of a nebulous Work class, but you don't need to work with shared data at all to use this pattern. Only the mutex and the condition variable are needed.

Work work;
boost::condition workAvailable; 
boost::mutex workMutex; 

void Producer() 
{
  {
    boost::mutex::scoped_lock lock(workMutex);
    UpdateWork(work);
    workAvailable.notify_one();  
  }
  boost::mutex::scoped_lock lock(workMutex);
  work.SetOver();
  workAvailable.notify_one();
}

void Consumer() 
{ 
  //This thread uses data protected by the work mutex
  boost::mutex::scoped_lock lock(workMutex);
  while(true) 
  { 
    //this call releases the work mutex
    //when this thread is notified, the mutex is re-acquired
    workAvailable.wait(lock); 
    //once we have the mutex we can work with shared data
    //which might require this thread to terminate
    if(work.Over())
    {
      return;
    }
    DoWork(work);
  }
}

The producer thread will create one unit of work, and then block. The consumer thread will do the work, and then block. Then the producer thread will set the termination condition and exit. The consumer will then exit.

christopher_f
I just noticed the comment about the blocking legacy call that his the heart of this problem. This definitely doesn't help answer the original question. I don't know if there is a safe way to terminate the blocking call in boost 1.33.1. If the legacy call is exception safe, later editions of boost can help.I considered deleting this, but I will leave this here, because the answer may be useful to someone other than the OP.
christopher_f