У меня есть многопоточное приложение, и мне нужно аккуратно остановить его при прерывании, завершении и т. Д. c. сигналы.
Здесь приведен фрагмент для иллюстрации соответствующих частей логики c.
std::atomic_bool running = true;
std::mutex mutex;
std::condition_variable condition;
void signal_handler(int signal)
{
// in another thread `[&]() { return !running || something_to_do_conditon; } == false`
// what means continue to wait
running = false;
condition.notify_one();
// another thread goes to sleep
}
void run() {
while(true) {
std::unique_lock lock(mutex);
condition.wait_for(lock, std::chrono::hours(1), [&]() { return !running || something_to_do_conditon; });
if (!running) {
return;
}
// do smth
}
}
int main()
{
// Install a signal handler
std::signal(SIGINT, signal_handler);
std::signal(SIGTERM, signal_handler);
std::thread thread(run);
thread.join();
}
Как вы можете видеть в signal_handler
, может быть ситуация, когда даже running
установлен на false
, condition
уведомляется, что все еще существует сценарий (описанный с помощью встроенных комментариев), когда поток переходит в спящий режим на 1 час. Это происходит потому, что вокруг переменной running
нет мьютекса. Это позволяет потоку заблокировать мьютекс и проверить условие непосредственно перед тем, как переменная будет установлена, переменная установлена. Если я добавлю что-то вроде
{
std::lock_guard<std::mutex> lock(mutex);
running = false;
}
в обработчик, которого следует избегать.
Тогда возникает вопрос, как использовать (возможно ли вообще) мьютексы без получения потенциальной тупика или каких-либо других проблемы. Любые другие уловки, чтобы ослабить спящую нить от сигнала.