Таким образом, вы хотите, чтобы первый поток, который нажимает 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.Вот что является исключением - альтернативный способ возврата из функции при возврате обычным способом не имеет смысла.