2

I am using boost library for threading and synchronization in my application.

First of all I must say exceptions within threads on synchronization is compilitey new thing for me. In any case below is the pseudo code what I want to achieve. I want synchronized threads to throw same exception that MAY have been thrown from the thread doing notify. How can I achieve this?

Could not find any topics from Stack Overflow regarding exception throwing with cross thread interaction using boost threading model

Many thanks in advance!

// mutex and scondition variable for the problem
mutable boost::mutex conditionMutex;
mutable boost::condition_variable condition;

inline void doTheThing() const {

   if (noone doing the thing) {
      try {
          doIt()
          // I succeeded
          failed = false;
          condition.notify_all();
      }
      catch (...) {
          // I failed to do it
          failed = true;
          condition.notify_all();
          throw
      }
  else {
      boost::mutex::scoped_lock lock(conditionMutex);
      condition.wait(lock);
      if (failed) {
          // throw the same exception that was thrown from 
          // thread doing notify_all
       }
  }

}

Lauri
  • 73
  • 8

1 Answers1

1

So you want the first thread that hits doTheThing() to call doIt(), and all subsequent threads that hit doTheThing() to wait for the first thread to finish calling doIt() before they proceed.

I think this should do the trick:

boost::mutex conditionMutex; // mutable qualifier not needed
bool failed = false;
bool done = false;

inline void doTheThing() const {

   boost::unique_lock uql(conditionMutex);

   if (!done) {
       done = true;
       try {
           doIt();
           failed = false;
       }
       catch (...) {
           failed = true;
           throw
       }
   }
   else if (failed)
   {
       uql.unlock();
       // now this thread knows that another thread called doIt() and an exception 
       // was thrown in that thread.
   }

}

Important notes:

Every thread that calls doTheThing() must take a lock. There is no way around this. You are synchronizing threads, and for a thread to know anything about what's happening in another thread, it must take a lock. (Or it can use atomic memory operations, but that's a more advanced technique.) The variables failed and done are protected by the conditionMutex.

C++ will call destructor of uql when the function exits normally or by throwing exception.

EDIT Oh, and as for throwing the exception to all the other threads, forget about that, it's almost impossible, and it isn't the way things are done in C++. Instead, each thread can check to see if the first thread successfully called doIt() in the place I've indicated above.

EDIT There is no language support for propagating an exception to another thread. You can generalize the problem of propagating exceptions to another thread to passing messages to another thread. There are lots of library solutions to the problem of passing messages between threads ( boost::asio::io_service::post() ), and you could pass a message that contains the exception, with instructions to throw that exception on receipt of message. It's a bad idea, though. Only throw exceptions when you have an error that prevents you from unwinding the call stack by ordinary function return. That's what an exception is--an alternative way to return from a function when returning the usual way doesn't make sense.

James Brock
  • 3,236
  • 1
  • 28
  • 33
  • Thanks for the answer. I know I need to lock the if statement to let others pass. I just left the locking out from pseudo code. Your solution has the requirement that every thread need to go through the doIt(). I want the blocked threads to wait for working thread to finish what it is doing. The actual problem was to how propagate possible exception to synchronized threads. So are you saying this is not possible at all? – Lauri Nov 14 '11 at 18:58
  • @Lauri 1 of 2: Look carefully, only the first thread goes through `doIt()`, the rest of the threads will skip `doIt()` after checking `done`. – James Brock Nov 15 '11 at 02:18
  • @Lauri 2 of 2: I clarified my answer, see above. – James Brock Nov 15 '11 at 02:30
  • If you're using the current version of C++ (C++11) there is language support for propagating exceptions to other threads. Use std::current_exception() to get an std::exception_ptr object, transfer that to another thread, and then call std::rethrow_exception() on it. Or you can use std::promise/std::future to do it. – bames53 Nov 15 '11 at 19:13