29

Possible Duplicate:
C++0x thread interruption

I am trying to kill/stop a c++ std::thread by using its thread object.

How can we do this?

Community
  • 1
  • 1
CPS
  • 667
  • 2
  • 6
  • 8

2 Answers2

41

@bamboon's answer is good, however I feel this deserves a stronger statement.

Whatever the language you use, your program will acquire and release resources: memory, file descriptors, ... For simple programs that are fired in one shots, leaking resources does not matter much: when the program ends modern OSes automatically take the resources back; however for long-running programs a basic requirement is not to leak resources, or at least not repetitively.

Therefore, you should have been taught from the beginning that when you acquire a resource you will have to ensure it is released at one point:

void foo(int i) {
    int* array = malloc(sizeof(int) * i);

    /* do something */

    free(array);
}

So, ask yourself the question:

  • what happens when I kill the program ?
  • what happens when I kill the thread ?

Well, as we said, when a program ends the OS gathers the resources back, so assuming (and this is some assumption) that you did not acquire a resource on another system OR that this system is well protected against such abuse, no harm, no foul.

However, when you kill a thread, the program still runs, thus the OS does not gather the resources back. You leaked memory, you locked a file for writing that you cannot unlock any longer, ... You shall not kill threads.

Higher level languages have a way to handle this: exceptions. Because programs should be exception safe anyway, Java (for example) will kill a thread by pausing it, throwing an exception at the point of execution, and gently unwind the stack. However there is no such facility in C++, yet.

Is it impossible ? No, obviously not. Actually, you could perfectly reuse the very same idea:

  • encapsulate std::thread, interruptible_thread class will also contain an interrupt flag
  • pass the address of the flag to std::thread when launching it, and store it in a thread-local way
  • instrument your code with check-points where you check whether the interrupt flag is set or not, and when it is throw an exception

That is:

// Synopsis
class interrupt_thread_exception;
class interruptible_thread;
void check_for_interrupt();

// Interrupt exception
class interrupt_thread_exception: public virtual std::exception {
public:
    virtual char const* what() const override { return "interrupt"; }
}; // class interrupt_thread_exception

// Interruptible thread
class interruptible_thread {
public:
    friend void check_for_interrupt();

    template <typename Function, typename... Args>
    interruptible_thread(Function&& fun, Args&&... args):
        _thread([](std::atomic_bool& f, Function&& fun, Args&&... args) {
                    _flag_ref = &f; fun(std::forward<Args>(args)...);
                },
                _flag,
                std::forward<Function>(fun),
                std::forward<Args>(args)...)
    {}

    bool stopping() const { return _flag.load(); }

    void stop() { _flag.store(true); }

private:
    static thread_local std::atomic_bool* _flag_ref = nullptr;

    std::atomic_bool _flag = false;
    std::thread _thread;
}; // class interruptible_thread

// Interruption checker
inline void check_for_interrupt() noexcept(false) {
    if (not interruptible_thread::_flag_ref) { return; }
    if (not interruptible_thread::_flag_ref->load()) { return; }

    throw interrupt_thread_exception();
} // check_for_interrupt

Now you can just sprinkle your threaded code with checks for interrupt at appropriate places.

Matthieu M.
  • 251,718
  • 39
  • 369
  • 642
  • 6
    +1, **this** is such an important concept. Threads are a in a different resource and security domain to processes. They are require a cooperative rather than 'adversarial' approach. Refactor the code so that threads can gracefully terminate when requested. – Brett Hale Dec 15 '12 at 15:22
  • 1
    `void foo(int)` is already not exception safe, if you have an interruption check in the middle of `/* do something */' it will still be wrong. – Jonathan Wakely Dec 16 '12 at 01:03
  • What signal? You're talking about throwing an exception on interruption, and some platforms do the same for pthread_cancel. If an exception is thrown it doesn't finish the function. – Jonathan Wakely Dec 16 '12 at 15:16
  • 2
    @JonathanWakely: Oups sorry, misread. My point was that exceptions are a *normal* mechanism in the language, therefore you can cater for them in the *normal* way: `try/catch` blocks, RAII, etc... whereas brutal interruption leaves you not tool to clean up. Note that I said *checks for interrupt **at appropriate places**.*! And you can still interrupt foo, as long as you catch the exception so that `free` is executed... but it was not really meant like that, I was more showing off the need for cleanup *explicitly* while a well built C++ program would use RAII, obviously. – Matthieu M. Dec 16 '12 at 15:32
  • 1
    Note that boost::thread's `terminate()` feature uses a broadly similar approach. Their terminology: "interruption points". An advantage of boost::thread over the code above: boost::thread also has built-in support for interruption of sleeping operations. E.g. of boost::thread::sleep_for(). – Nanno Langstraat Dec 12 '13 at 13:05
  • 1
    It is not always possible to terminate thread this ways. What if it performs some blocking io, like calling `getline`. And there is no standard way to do it in non-blocking way. – Simon Mar 22 '14 at 12:15
  • @Simon: I agree, but it's still the best option. Unfortunately concurrent execution can be *extremely* invasive, and stopping a thread of execution is one of the road-blocks; VM code can get around it by injecting code (and triggering an exception that unwinds the thread) but native code require cooperation. The only way to get I/O to play nice is to standardize a way for I/O to be interruptible... and were are not there yet :x – Matthieu M. Mar 22 '14 at 15:35
  • 1
    @MatthieuM. Code running on a VM gives you a some flexibility but not soundness: that user code still has user invariants and there is no way for the VM to restore or even know them. – curiousguy Jan 18 '20 at 20:31
29

You can't.

std::threads are not interruptible. You can use boost::thread which offers this feature.

Boost does this by defining "interrupt points" on which the thread will end if it is interrupted and reaches such a point.

Nevertheless, most of the time thinking about a redesign might be the cleanest and easiest way to reach what you are trying to achieve.

If you are still looking for a C++11 implementation of interruptible threads checkout out Anthony Williams (owner of boost thread) book "C++ Concurrency in Action". He goes through a basic implementation of how such a thing can be achieved.

std::thread::native_handle gives you access to the platform specific underlying thread handle which might support interrupting, however this approach makes your code unportable and probably not cleaner in any way.

Stephan Dollberg
  • 27,667
  • 11
  • 72
  • 104
  • Interrupting the linux "process" corresponding to an high level C++ thread would stop the use of the CPU, but it could never deallocate other resources or restore internal data structures to their previous state, or even to any consistent state if they were being modified, or de-lock mutexes, etc. – curiousguy Jan 18 '20 at 20:28