Как можно чисто завершить процесс в С++ 11?

Интересно, есть ли хороший способ через некоторое время завершить мой процесс, написанный на С++ 11?

В моем процессе у меня есть основной класс с чистой виртуальной функцией run(), выполняющей основную программу, которая может быть заблокирована в коммуникационных процессах. Я хочу, чтобы моя функция run() была принудительно завершена через некоторое время (даже если она заблокирована) и вызывался деструктор моего основного класса (и всех деструкторов членов).

Теперь у меня есть таймер, который вызывает std::terminate через обратный вызов.

namespace Timer
{
    void start(Duration time, function<void()> task)
    {
        thread([time, task]() {
            this_thread::sleep_for(time);
            task();
        }).detach();
    }
}

person didil    schedule 10.11.2015    source источник
comment
Если функция run() не вернется, вы не сможете корректно завершить программу. Возможно, вы могли бы запустить run() в потоке и вызвать для него thread::detach(): будут вызваны основные деструкторы, но я бы не назвал это чистым.   -  person rodrigo    schedule 10.11.2015
comment
У меня тоже была эта проблема с программой, которая могла застрять в общении. Я добавил к нему механизм сердцебиения, поэтому я знаю, что каждые X секунд (в моем случае каждые 45 секунд) сообщение будет получено и отправлено, а затем установлен тайм-аут в минуту. Поэтому я никогда не попадаю в ситуацию, когда застреваю и жду сообщения. Конечно, худшим случаем было то, что программе требовалось 45 секунд для закрытия, но было ли это чисто!   -  person Nidhoegger    schedule 10.11.2015
comment
Если (неотсоединенный) поток заблокирован, его нельзя корректно завершить без предварительной разблокировки. Вы должны управлять этим синтаксически, например,, используя ожидание/уведомление или периодически проверяя статус, используя wait_for или подобное.   -  person Snps    schedule 10.11.2015
comment
Я не могу разблокировать лишние библиотеки и не хочу ждать тайм-аута связи (это не связано с проблемами связи). Я просто хочу заставить программу завершить работу через некоторое время, чтобы вовремя остановить процесс (вызвав все деструкторы). Если основная программа завершилась раньше таймера, она также должна завершиться должным образом (время выполнения может быть меньше таймера, но не больше).   -  person didil    schedule 10.11.2015
comment
Оберните run нитью. Если это не закончится вовремя, просто выполните обычный выход. Вы закроете все, что выше run, правильно. Вы не контролируете вещи ниже run, в любом случае нет никакой надежды заставить их изящно выйти.   -  person n. 1.8e9-where's-my-share m.    schedule 10.11.2015
comment
Это решение, которое я сохраню.   -  person didil    schedule 10.11.2015


Ответы (3)


Настоящим решением было бы устранение причины, а не симптома:

  • симптом: run функция никогда не заканчивается
  • причина: запрос связи никогда не заканчивается

Большинство функций связи (ввода) являются прерываемыми или имеют собственные тайм-ауты. Если ваши коммуникационные подпрограммы не имеют собственных тайм-аутов, вы могли бы (возможно) обернуть их таким образом, используя вызов alarm Posix, который должен чисто прервать их и позволить функции выполнения завершиться корректно.

Вам просто нужно обратить внимание на тот факт, что alarm использует сигнал под капотом, поэтому вы не должны блокировать SIG_ALRM, но вы можете использовать его для установки обработчика сигнала, который где-то сохраняет то, что было вызвано.

ИМХО, это будет проще, чище и с лучшим разделением ответственности, чем прямое завершение программы с помощью std::terminate.

Выше рассматривается только случай, когда run никогда не заканчивается. Если вы хотите ограничить время его выполнения, вы должны определить прерываемые места в своем коде, где вы проверяете, не исчерпано ли разрешенное время выполнения, и постоянно устанавливать тайм-ауты для всех, возможно, блокирующих коммуникационных операций ввода-вывода.

person Serge Ballesta    schedule 10.11.2015
comment
Вы не отвечаете на мой вопрос. run() заканчивается. Но это может занять больше времени, чем ожидалось. Я хочу принудительно завершить run(), если это было слишком долго. Он может быть заблокирован при чтении сообщения или нет. - person didil; 10.11.2015

Я предполагаю, что вы работаете в Linux или какой-либо другой системе POSIX. Циклы событий и опросы не стандартизированы в C++11 и требуют определенных особенностей операционной системы.

Ваш цикл событий никогда не должен блокироваться в течение длительного времени. У него должен быть некоторый конечный и не слишком большой тайм-аут. В POSIX используйте poll(2) в цикле обработки событий. с разумным тайм-аутом (например, секунду). В качестве альтернативы можно использовать канал (внутренний по отношению к процессу), чтобы запустить цикл обработки событий (чтобы какой-нибудь другой поток или даже обработчик сигнала write(2) в этом канале, и цикл событий будет опрашивать его и read, и может остановиться, следовательно, вернуться из run)

См. также это и это для соответствующих советов.

person Basile Starynkevitch    schedule 10.11.2015

Лучшее решение — обернуть run() в поток.

std::thread([&]()
{
   run();
   finish.notify_all();
}).detach();

std::unique_lock<std::mutex> lock(waitFinish);
finish.wait_for(lock, time);
person didil    schedule 10.11.2015