C++0x 线程中断

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2790346/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:41:08  来源:igfitidea点击:

C++0x thread interruption

c++multithreadingc++11

提问by Nicola Bonelli

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.

根据 C++0x 最终草案,无法请求终止线程。也就是说,如果需要,我们需要实施自己动手的解决方案。

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

另一方面 boost::thread 提供了一种以安全方式中断线程的机制。

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

在您看来,最好的解决方案是什么?设计自己的合作“中断机制”还是本地化?

回答by peterchen

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

所有的语言规范都说支持不是内置在语言中的。 boost::thread::interrupt也需要线程函数的一些支持:

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.

我不确定您所说的“本地化”是什么意思 - 没有本地支持,除非您对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.

也可以提出“不要对控制流使用异常”,但与搞乱线程相比,这只是一个指导方针。

回答by Vicente Botet Escriba

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.

使用本机句柄取消线程在 C++ 中是一个糟糕的选择,因为您需要销毁所有堆栈分配的对象。这是他们不包括取消操作的主要原因。

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.

Boost.Thread 提供了一种中断机制,需要在任何等待原语上进行池化。由于作为通用机制,这可能很昂贵,因此标准并未包含它。

You will need to implement it by yourself. See my answer hereto 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.

您需要自己实现它。见我的答案在这里,就如何通过自己实现这个类似的问题。要完成解决方案,应在中断为真时抛出中断,并且线程应捕获此中断并完成。

回答by Marcelo Cantos

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::interruptsolution 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 TerminateThreadfunction 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.

boost::thread::interrupt解决方案通过很好地询问而起作用。它只会中断一个线程做一些可中断的事情,比如等待 Boost.Thread 条件变量,或者如果线程在调用中断后做了这些事情之一。即便如此,线程也不会像 Win32 的TerminateThread函数那样毫不客气地通过绞肉机,它只会引发一个异常,如果您是一个乖巧的编码员并在各处使用 RAII,那么它会自行清理并优雅地退出线程。

回答by user328543

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.

如果您只想等待线程完成,请使用 join() 或 future。

回答by Michael Aaron Safyan

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.

实施自己动手的解决方案最有意义,而且确实不应该那么难。您将需要一个同步读/写的共享变量,指示线程是否被要求终止,并且当线程处于可以安全中断的状态时,它会定期从该变量中读取。当你想中断一个线程时,你只需同步写入这个变量,然后加入线程。假设它配合得当,应该注意到该变量已经被写入并关闭,导致join函数不再阻塞。

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.

如果你是土生土长的,你不会因此得到任何东西;您将简单地抛弃标准和跨平台 OOP 线程机制的所有好处。为了使您的代码正确无误,线程需要协同关闭,这意味着上述通信。

回答by dimitri

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

这是我对线程取消器(用于 C++0x)的简单实现。我希望它会很有用。

// 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;
}

回答by Fabio Ceconello

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.

我的线程实现使用 pimpl 惯用语,在 Impl 类中,我为我支持的每个操作系统都有一个版本,还有一个使用 boost,因此我可以决定在构建项目时使用哪一个。

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,它只有操作系统提供的基本服务;另一个是SafeThread,它继承自Thread,具有协同中断的方法。

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.

Thread 有一个 terminate() 方法可以执行侵入式终止。它是一个在 SafeThread 中重载的虚方法,在那里它发出一个事件对象的信号。有一个(静态) yeld() 方法,运行线程应该不时调用它;此方法检查事件对象是否已发出信号,如果是,则抛出在线程入口点的调用者处捕获的异常,从而终止线程。当它这样做时,它会向第二个事件对象发出信号,因此 terminate() 的调用者可以知道线程已安全停止。

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.

对于存在死锁风险的情况,SafeThread::terminate() 可以接受超时参数。如果超时到期,它会调用 Thread::terminate(),从而侵入性地杀死线程。当你有一些你无法控制的东西(比如第三方 API)或者在死锁比资源泄漏等造成更大损害的情况下,这是最后的资源。

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.

希望这对您的决定有用,并会让您对我的设计选择有足够清晰的了解。如果没有,我可以发布代码片段以澄清您是否愿意。

回答by Alex F

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.

我同意这个决定。例如,.NET 允许中止任何工作线程,我从不使用此功能,也不建议任何专业程序员执行此操作。我想自己决定,什么时候工作线程可能会被中断,以及这样做的方法是什么。对于硬件、I/O、UI 和其他线程来说是不同的。如果线程可能在任何地方停止,这可能会导致未定义的程序行为,包括资源管理、事务等。