Синхронизация C ++ и обработка исключений в кросс-потоках - PullRequest
2 голосов
/ 14 ноября 2011

Я использую библиотеку Boost для многопоточности и синхронизации в моем приложении.

Прежде всего я должен сказать, что исключения в потоках при синхронизации - это совершенно новая вещь для меня.В любом случае ниже приведен псевдокод, которого я хочу достичь.Я хочу, чтобы синхронизированные потоки выдавали то же исключение, которое МОЖЕТ быть выброшено из потока, выполняющего уведомление.Как я могу этого достичь?

Не удалось найти в Stack Overflow ни одной темы, касающейся выброса исключений при взаимодействии с несколькими потоками с использованием модели ускорения потоков

Большое спасибо заранее!

// 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
       }
  }

}

1 Ответ

1 голос
/ 14 ноября 2011

Таким образом, вы хотите, чтобы первый поток, который нажимает doTheThing(), вызвал doIt(), а все последующие потоки, которые нажимали doTheThing(), ожидали, пока первый поток завершит вызов doIt(), прежде чем они продолжат.

Я думаю, что это должно сработать:

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.
   }

}

Важные замечания:

Каждый поток, который вызывает doTheThing(), должен получить блокировку.Обойти это невозможно.Вы синхронизируете потоки, и чтобы поток узнал что-то о том, что происходит в другом потоке, он должен получить блокировку.(Или он может использовать атомарные операции с памятью, но это более продвинутый метод.) Переменные failed и done защищены conditionMutex.

C ++ вызовет деструктор uql, когдаФункция обычно завершает работу или , генерируя исключение.

EDIT О, а что касается выдачи исключения всем остальным потокам, забудьте об этом, это практически невозможно, ив C ++ все не так.Вместо этого каждый поток может проверить, успешно ли первый поток вызвал doIt() в указанном выше месте.

РЕДАКТИРОВАТЬ Нет языковой поддержки для передачи исключения другомунить.Вы можете обобщить проблему передачи исключений в другой поток на передачи сообщений в другой поток .Существует множество библиотечных решений проблемы передачи сообщений между потоками ( boost :: asio :: io_service :: post () ), и вы можете передать сообщение, содержащее исключение, с инструкциями для выбросаэто исключение при получении сообщения.Хотя это плохая идея.Бросать исключения только тогда, когда у вас есть ошибка, которая не позволяет вам раскрутить стек вызовов с помощью обычной функции return.Вот что является исключением - альтернативный способ возврата из функции при возврате обычным способом не имеет смысла.

...