1

I wonder if there is a good way to terminate my process written in C++11 after a while?

In my process I have a main class with a pure virtual function run() running the main program that could be blocked in communication processes. I want my run() function to be forced to finish after a while (even if blocked) and the destructor of my main class (and all the destructors of the members) to be called.

Now I have a timer that call std::terminate via a callback.

namespace Timer
{
    void start(Duration time, function<void()> task)
    {
        thread([time, task]() {
            this_thread::sleep_for(time);
            task();
        }).detach();
    }
}
6
  • 1
    If the run() function will not return, you cannot end the program cleanly. Maybe you could run run() in a thread, and call thread::detach() on it: main destructors will be called, but I wouldn't call it clean.
    – rodrigo
    Commented Nov 10, 2015 at 8:48
  • 1
    I had this issue, too with a program that could be stuck in communication. I have added a heartbeat meachanism to it, so I know every X seconds (in my case every 45 seconds) a message will be received and sent and then put in a timeout of a minute. So I never get in a case where I am stuck and waiting for a message. Of course the worst case was that the program needed 45 seconds to shut down, but did it clean!
    – Nidhoegger
    Commented Nov 10, 2015 at 8:50
  • If a (non-detached) thread is blocked it can't be gracefully terminated without first unblocking it. You must control this syntactically by, e.g., using wait/notify or periodically check status using wait_for or similar.
    – Felix Glas
    Commented Nov 10, 2015 at 8:52
  • I cannot unblock extra libraries and I don't want to wait the communication timeout (this is not related to communication issues). I simply want to force the program to finish after a while to be able to stop properly the process (calling all the destructors) in the time. If the main program finished before the timer, it should also terminate properly (the run time can be shorter than the timer but never longer).
    – didil
    Commented Nov 10, 2015 at 9:21
  • 1
    Wrap run in a thread. If it doesn't finish in time, just do a normal exit. You will get everything above run shut down properly. You don't control things below run, there's no hope of making them exit gracefully anyway. Commented Nov 10, 2015 at 11:02

3 Answers 3

2

The real solution would be to deal with the cause and not the symptom:

  • symptom: run function never ends
  • cause: a communication request never ends

Most communication (input) functions are interruptible, or have native timeouts. If your communication routines have no native timeouts, you could (maybe) wrap them in a way using an alarm Posix call that should cleanly interrupt them and allow the run function to cleanly exit.

You just have to pay attention to the fact that alarm uses signal under the hood so you must not block SIG_ALRM, but you can use it to install a signal handler that stores somewhere that is has been called.

IMHO, it will be simpler, cleaner, and with a better separation of concern than directly terminating the program with std::terminate.

Above only deals with the case where run never ends. If you want to limit the time it runs, you should identify interruptible places in your code where you test if allowed run time is exhausted, and consistently put timeouts on all possibly blocking communication IO.

1
  • You're not answering my question. run() does end. But it could take more time than expected. I want to force run() to finish in the case it was too long. It could be blocked in a communication read or not.
    – didil
    Commented Nov 10, 2015 at 10:03
1

I guess you are on Linux or some other POSIX system. Event loops and polling are not standardized in C++11 and need operating system specific things.

Your event loop should never be blocked for a long time. It should have some finite -and not too big- timeout. On POSIX, use poll(2) in your event loop with a reasonable timeout (e.g. a second). Alternatively, use a pipe (internal to the process) to trigger the event loop (so some other thread -or even a signal handler- would write(2) on that pipe, and the event loop would poll it and read it, and might stop, hence returning from run)

See also this and that for related hints.

0
1

The best solution is to wrap run() in a thread.

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

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.