58

According to the C++0x final draft, there's no way to request a thread to terminate. That said, if required we need to implement a do-it-yourself solution.

On the other hand boost::thread provides a mechanism to interrupt a thread in a safe manner.

In your opinion, what's the best solution? Designing your own cooperative 'interruption mechanism' or going native?

Nicola Bonelli
  • 8,101
  • 4
  • 26
  • 35
  • 3
    Worth noting that if you can just kill a thread, that might leave allocated resources in memory(since the thread was killed before those were deleted). So I think this is, at least for most cases, a good decision. – luiscubal May 07 '10 at 17:22
  • 10
    There are even worse things than leaks - such as incomplete transactions, a corrupted heap or locks still held. – peterchen May 09 '10 at 12:10
  • 11
    if you care about correctness, you don't really have a choice: then threads can *only* be interrupted cooperatively, when they're in predefined "interuptable" states. – jalf May 09 '10 at 12:57
  • 10
    Killing a thread is putting a noose around all the other threads' necks. Just don't do it, unless you're a cold blooded thread killer... – Jörgen Sigvardsson Aug 18 '11 at 10:30
  • possible duplicate of [How do I terminate a thread in C++11?](http://stackoverflow.com/questions/12207684/how-do-i-terminate-a-thread-in-c11) Choosing the other because it is a bit more general. – Ciro Santilli OurBigBook.com Jun 15 '15 at 10:02

8 Answers8

17

All the language specification says that the support isn't built into the language. boost::thread::interrupt needs some support from the thread function, too:

When the interrupted thread next executes one of the specified interruption points (or if it is currently blocked whilst executing one)

i.e. when the thread function doesn't give the caller a chance to interrupt, you are still stuck.

I'm not sure what you mean with "going native" - there is no native support, unless you are spellbound to boost:threads.

Still, I'd use an explicit mechanism. You have to think about having enough interruption points anyway, why not make them explicit? The extra code is usually marginal in my experience, though you may need to change some waits from single-object to multiple-objects, which - depending on your library - may look uglier.


One could also pull the "don't use exceptions for control flow", but compared to messing around with threads, this is just a guideline.

peterchen
  • 40,917
  • 20
  • 104
  • 186
  • The other option, also mentioned in http://www2.research.att.com/~bs/C++0xFAQ.html#std-thread, is `going native`, that is using thread::native_handle() to gain access to the operating system thread handle in order to implement the thread interruption. – Nicola Bonelli May 09 '10 at 12:30
  • Thanks, Nicola. IMO native vs. library depends on other things - generally, I wouldn't **rely** on `interrupt`. – peterchen May 09 '10 at 15:58
10

Using native handle to cancel a thread is a bad option in C++ as you need to destroy all the stack allocated objects. This was the main reason they don't included a cancel operation.

Boost.Thread provides an interrupt mechanism, that needs to pool on any waiting primitive. As this can be expensive as a general mechanism, the standard has not included it.

You will need to implement it by yourself. See my answer here to a similar question on how to implement this by yourself. To complete the solution an interruption should be throw when interrupted is true and the thread should catch this interruption and finish.

Community
  • 1
  • 1
Vicente Botet Escriba
  • 4,305
  • 1
  • 25
  • 39
7

Here is my humble implementation of a thread canceller (for C++0x). I hope it will be useful.

// Class cancellation_point
#include <mutex>
#include <condition_variable>

struct cancelled_error {};

class cancellation_point
{
public:
    cancellation_point(): stop_(false) {}

    void cancel() {
        std::unique_lock<std::mutex> lock(mutex_);
        stop_ = true;
        cond_.notify_all();
    }

    template <typename P>
    void wait(const P& period) {
        std::unique_lock<std::mutex> lock(mutex_);
        if (stop_ || cond_.wait_for(lock, period) == std::cv_status::no_timeout) {
            stop_ = false;
            throw cancelled_error();
        }
    }
private:
    bool stop_;
    std::mutex mutex_;
    std::condition_variable cond_;
};


// Usage example
#include <thread>
#include <iostream>

class ThreadExample
{
public:
    void start() {
        thread_ = std::unique_ptr<std::thread>(
            new std::thread(std::bind(&ThreadExample::run, this)));
    }
    void stop() {
        cpoint_.cancel();
        thread_->join();
    }
private:
    void run() {
        std::cout << "thread started\n";
        try {
            while (true) {
                cpoint_.wait(std::chrono::seconds(1));
            }
        } catch (const cancelled_error&) {
            std::cout << "thread cancelled\n";
        }
    }
    std::unique_ptr<std::thread> thread_;
    cancellation_point cpoint_;
};

int main() {
    ThreadExample ex;
    ex.start();
    ex.stop();
    return 0;
}
dimitri
  • 874
  • 8
  • 11
  • I modified the function cancellation_point::wait to void Cancellation::wait(int seconds) and inside it I instantiated a variable `auto t = std::chrono::seconds(seconds);` that I pass to the wait_for function of the conditional variable as the duration argument. This to avoid the grief of template argument deduction using the original code as is. – Pablo Adames Sep 12 '22 at 22:04
6

It is unsafe to terminate a thread preemptively because the state of the entire process becomes indeterminate after that point. The thread might have acquired a critical section prior to being terminated. That critical section will now never be released. The heap could become permanently locked, and so on.

The boost::thread::interrupt solution works by asking nicely. It will only interrupt a thread doing something thats interruptible, like waiting on a Boost.Thread condition variable, or if the thread does one of these things after interrupt is called. Even then, the thread isn't unceremoniously put through the meat grinder as, say, Win32's TerminateThread function does, it simply induces an exception, which, if you've been a well-behaved coder and used RAII everywhere, will clean up after itself and gracefully exit the thread.

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
5

Implementing a do-it-yourself solution makes the most sense, and it really should not be that hard to do. You will need a shared variable that you read/write synchronously, indicating whether the thread is being asked to terminate, and your thread periodically reads from this variable when it is in a state where it can safely be interrupted. When you want to interrupt a thread, you simply write synchronously to this variable, and then you join the thread. Assuming it cooperates appropriately, it should notice that that the variable has been written and shut down, resulting in the join function no longer blocking.

If you were to go native, you would not gain anything by it; you would simply throw out all the benefits of a standard and cross-platform OOP threading mechanism. In order for your code to be correct, the thread would need to shut down cooperatively, which implies the communication described above.

Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
4

Its unsafe to terminate a thread, since you would have no control over the state of any data-structures is was working on at that moment.

If you want to interrupt a running thread, you have to implement your own mechanism. IMHO if you need that, your design is not prepared for multiple threads.

If you just want to wait for a thread to finish, use join() or a future.

user328543
  • 577
  • 3
  • 9
  • 57
    There are a lot of reasons to interrupt a running thread, those don't imply bad design at all. – Chris O May 15 '10 at 21:25
  • 31
    -1, You completely ignore the *way* interruption is achieved in boost. It is a deterministic way involving throwing an exception from some predefined spots. The integrity of the data that the thread was working on is guaranteed by exception safety. – Yakov Galka Jun 21 '11 at 21:05
  • 6
    For example: In a heuristic algorithm, there might be several threads searching for solution in different spaces. Once the solution is found by one thread, other threads should be killed or cancelled. Ok, I agree we can hand code it too but it looks like a basic requirement. – balki Feb 11 '12 at 03:29
  • 1
    To expand a little on ybungalobill's answer: boost::thread's "terminate()" call does NOT (necessarily) use the operating system's crude thread termination mechanism. Instead, it throws a special exception at specific "interruption points" that are under the control of the application programmer. – Nanno Langstraat Dec 12 '13 at 12:03
  • Ignoring many details, a thread interruption point like 'boost::this_thread::sleep()' /might/ look like this inside: pthread_cond_wait(&hidden_cond, &hidden_mutex); if (hidden_terminate_flag) throw boost::thread_terminated(); (Use of a pthread condition variable will allow termination of a sleeping thread without polling.) Mind you, this is pure speculation; boost::thread's actual implementation may be completely different. It's just to give an impression of how boost::thread's rules offer good-enough *standard* thread interruption that stays within C++'s normal mechanisms. – Nanno Langstraat Dec 12 '13 at 12:45
4

My implementation of threads uses the pimpl idiom, and in the Impl class I have one version for each OS I support and also one that uses boost, so I can decide which one to use when building the project.

I decided to make two classes: one is Thread, which has only the basic, OS-provided, services; and the other is SafeThread, which inherits from Thread and has method for collaborative interruption.

Thread has a terminate() method that does an intrusive termination. It is a virtual method which is overloaded in SafeThread, where it signals an event object. There's a (static) yeld() method which the running thread should call from time to time; this methods checks if the event object is signaled and, if yes, throws an exception caught at the caller of the thread entry point, thereby terminating the thread. When it does so it signals a second event object so the caller of terminate() can know that the thread was safely stopped.

For cases in which there's a risk of deadlock, SafeThread::terminate() can accept a timeout parameter. If the timeout expires, it calls Thread::terminate(), thus killing intrusively the thread. This is a last-resource when you have something you can't control (like a third-party API) or in situations in which a deadlock does more damage than resource leaks and the like.

Hope this'll be useful for your decision and will give you a clear enough picture about my design choices. If not, I can post code fragments to clarify if you want.

Fabio Ceconello
  • 15,819
  • 5
  • 38
  • 51
  • No offense, but what does your particular thread implementation have to do with `std::thread` and `boost::thread`? – Billy ONeal May 16 '10 at 23:57
  • Sorry if I wasn't clear enough, the recommendation I wanted to give was not to use either of them directly, instead have your own wrapper classes that could use them internally or not, and according to your choice complement them with low-level code without making your application dependent from it. Given the current state of multithreading support in C++, I think this approach is necessary and solves the posed problem. Bottom line, my answer to the question would be: write your own classes, but not necessarily the code to support them: use boost, std or your own code where convenient. – Fabio Ceconello May 17 '10 at 01:25
2

I agree with this decision. For example, .NET allows to abort any worker thread, and I never use this feature and don't recommend to do this to any professional programmer. I want to decide myself, when a worker thread may be interrupted, and what is the way to do this. It is different for hardware, I/O, UI and other threads. If thread may be stopped at any place, this may cause undefined program behavior with resource management, transactions etc.

Alex F
  • 42,307
  • 41
  • 144
  • 212