Обработка исключений для <mutex> и <condition_variable>
Полагая
- no undefined,
- нет взаимоблокировок,
- мьютексы заблокированы и разблокированы в правильном порядке правильными потоками правильное количество раз,
- нерекурсивные мьютексы не блокируются несколько раз,
- блокировка рекурсивных мьютексов не превышает максимального уровня владения,
- предикаты не передаются в переменные условия throw, а
- используются только часы, точки времени и длительности, предоставляемые стандартной библиотекой, с мьютексами
std::
и переменными условия
гарантировано, что работа над различными типами мутетексов std::
и переменными условия (кроме их построения) не генерирует никаких исключений (особенно типа std::system_error
)?
Например, в случае таких методов, как:
void MyClass::setVariable() {
std::lock_guard<std::mutex> const guard(m_mutex);
m_var = 42; // m_var is of type int
m_conditionVariable.notify_all();
}
void MyClass::waitVariable() {
std::unique_lock<std::mutex> lock(m_mutex);
m_conditionVariable.wait(lock, [this]() noexcept { return m_var == 42; });
}
Можно ли предположить noexcept
или написать несколько блоков try-catch вокруг звонков? Или есть какие-либо оговорки?
Пожалуйста, рассмотрите все типы мьютексов и переменных условий в С++ 11, С++ 14 и более поздних версиях.
Ответы
Ответ 1
Благодарим ссылка T.C. теперь я бы сказал, что да - ваш код должен быть в безопасности. Так как в будущем стандарт device_or_resource_busy
будет удален, и, как автор проблемы говорит, что эта ситуация не может произойти разумным образом, есть только 2 возможности для lock
:
(13.1) - operation_not_permitted - если поток не имеет привилегии для выполнения операции.
(13.2) - resource_deadlock_would_occur - если реализация обнаруживает что произойдет тупик.
И обе эти ситуации исключаются из ваших предварительных условий. Поэтому ваш код должен быть безопасным для использования noexcept.
Ответ 2
Короткий ответ: Нет (извините)
Любая из этих операций будет бросать std::system_error
, если основной объект синхронизации не сможет выполнить свою операцию.
Это связано с тем, что правильная работа примитивов синхронизации зависит от:
Несмотря на справедливость, если (1) происходит, вероятно, пора перепроектировать приложение или запустить его на менее загруженной машине.
И если (2) происходит, программа не логически последовательна.
При этом
или нужно написать несколько блоков try-catch вокруг звонков?
Также нет.
Вы должны написать блоки try/catch при следующих условиях:
-
Если программа в состоянии сделать что-то полезное о состоянии ошибки (например, отремонтировать ее или попросить пользователя, хочет ли он повторить попытку)
-
Вы хотели бы добавить некоторую информацию об ошибке и повторно бросить ее, чтобы предоставить диагностический маршрут (вложенные исключения, например)
-
Вы хотите зарегистрировать сбой и продолжить.
В противном случае вся обработка исключений С++ заключается в том, что вы разрешаете RAII позаботиться о повторном сбое ресурсов и разрешить исключению перетекать в стек вызовов, пока не найдет обработчик, который хочет обработать его.
пример создания дорожки для панировки:
void wait_for_object()
try
{
_x.wait(); // let say it throws a system_error on a loaded system
}
catch(...)
{
std::throw_with_nested(std::runtime_error(__func__));
}