I want to kill a std::thread using its thread object? [duplicate]
@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:
// Synopsisclass interrupt_thread_exception;class interruptible_thread;void check_for_interrupt();// Interrupt exceptionclass interrupt_thread_exception: public virtual std::exception {public: virtual char const* what() const override { return "interrupt"; }}; // class interrupt_thread_exception// Interruptible threadclass 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 checkerinline 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.
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.