10

I'm using the boost::thread library (V1.44) to support threads in my C++ project.

The user needs to be able to pause the execution of a test loop, that's running in its own thread, for an unlimited amount of time and be able to resume it whenever he pleases.

Under Windows I solved it like this

bool ContintueLoop(){
if(testLoopPaused){ //testLoopPaused can be set by the user via  GUI elements
  try{
      boost::this_thread::interruptible_wait( 2147483648 ); //that's very ugly,
      // somebody knows the right way to pause it for a unlimited time?
      return true;
     }
  catch( boost::thread_interrupted& e ){ //when the user selects resume the 
      // the thread is interrupted and continues from here
      testLoopPaused = false;
      return true;
     }
if( ... ) //test for other flags like endTestLoop etc.
  ....
}

This works without any problems, even though it would be nice to know the correct value for an unlimited interruption.

I started to implement a linux version of my program, but I ran into the problem that I get the compiler error

error: interruptible_wait is not a member of boost::this_thread

Question: What's a good way to pause a boost::thread for an unlimited time (until the user decides to resume it)

Thank you very much

zitroneneis
  • 1,037
  • 1
  • 12
  • 21
  • Isn't there any command like `Suspend()` ? – ali_bahoo Dec 16 '10 at 09:34
  • @sad_man, no there isn't. There's a sleep function which will suspend the thread for defined amount of time, but I don't think the suspended thread can be resumed at a random time – zitroneneis Dec 16 '10 at 09:48

2 Answers2

18

I'm not aware of any way to pause a thread at an arbitrary point using boost::thread, however, the situtation you've described can be implemented using a boolean, mutex and condition variable.

bool m_pause; // initialise to false in constructor!
boost::mutex m_pause_mutex;
boost::condition_variable m_pause_changed;

void block_while_paused()
{
    boost::unique_lock<boost::mutex> lock(m_pause_mutex);
    while(m_pause)
    {
        m_pause_changed.wait(lock);
    }
}

void set_paused(bool new_value)
{
    {
        boost::unique_lock<boost::mutex> lock(m_pause_mutex);
        m_pause = new_value;
    }

    m_pause_changed.notify_all();
}

So, in your worker thread you can periodically call block_while_paused() which won't return until m_pause is set to false. In your main thread you call set_paused(value) to update the value of the pause variable in a thread safe manner.

Disclaimer: This is adapted from some similar code we have here, but I haven't tried to compile the adapted code, let alone verify it actually works :)

Adam Bowen
  • 10,820
  • 6
  • 36
  • 41
  • @Adam, that look very promising. I will try to implement it and report back, thanks! – zitroneneis Dec 16 '10 at 09:46
  • If you've got some kind of class that represents your worker thread the best thing to do would be to place all that in the class, making everything but `set_paused` private so that it can't be misused. The only thing to note is that `mutex` and `condition_variable` can't be copied, which (depending on how you're creating your thread with boost) can be a slight inconvenience. – Adam Bowen Dec 16 '10 at 09:51
  • Now just put in a queue and you can control the thread completely ;) @ Adam: small remark, you don't have to unlock to notify_all(), which would simplify your code a little bit. – stefaanv Dec 16 '10 at 10:43
  • I know, but I generally try to hold a mutex for the shortest time possible :). – Adam Bowen Dec 16 '10 at 10:51
  • @Adam: a bit late reaction, but I was thinking of the situation where the caller released the lock and then gets pre-empted. The thread wants to pause, so it takes the lock checks the condition and gets pre-empted. Then the caller notifies before the thread waits, so the threads misses the notify and will not react. You might think that this never happens, but it might be worthwhile checking when in load-situations some threads don't react... – stefaanv Dec 17 '10 at 08:53
  • @stefaanv I'm not sure I fully understand you. If `block_while_paused` cannot obtain the lock then it will have to wait until `set_paused` has completed - there will be no need to wait on the condition because `m_pause` is inspected before it waits. AFAIK you always need to implement blocking on a condition this way in order to avoid the race conditions you describe. Also, for the record, the pattern above is almost exactly the pattern used in the example in the boost documentation. – Adam Bowen Dec 17 '10 at 09:14
  • @Adam: sorry for my messy mind, I stand corrected. It will react because the run condition is met (pause is false) and later on, it might get a spurious notify, so it checks pause, which is true: no problem with unlocking before notifying. – stefaanv Dec 17 '10 at 10:30
  • @Adam, I implemented this solution and it works like a charm. Very nice way to pause a thread. Thank you for your advice! – zitroneneis Dec 17 '10 at 11:47
1

If anybody still needs mentioned functionality (sleeping thread until an event occurs) and is comfortable using boost libraries then Boost.Interprocess library provides Semaphore mechanism which can be used as described in question.

Krzych
  • 83
  • 1
  • 6