我想使用它的线程对象杀死一个 std::thread?[复制]

I want to kill a std::thread using its thread object? [duplicate]

提问人:CPS 提问时间:12/15/2012 最后编辑:CommunityCPS 更新时间:9/15/2019 访问量:60081

问:

这个问题在这里已经有答案了:
10年前关闭。

可能的重复项:
C++0x 线程中断

我正在尝试使用其线程对象杀死/停止 c++ std::thread。

我们怎样才能做到这一点?

C++ 多线程 C++11 标准 stdthread

评论

2赞 zch 12/15/2012
相关新闻: stackoverflow.com/questions/2790346/c0x-thread-interruption

答:

33赞 Stephan Dollberg 12/15/2012 #1

你不能。

std::threads是不可中断的。您可以使用提供此功能的。boost::thread

Boost 通过定义“中断点”来实现这一点,如果线程被中断并达到这样的点,线程将在该中断点上结束。

然而,大多数时候,考虑重新设计可能是达到您想要实现的目标的最干净和最简单的方法。

如果你还在寻找可中断线程的C++11实现,请查看Anthony Williams(boost线程的所有者)的书“C++并发在行动”。他经历了如何实现这样的事情的基本实现。

std::thread::native_handle使您可以访问特定于平台的底层线程句柄,该句柄可能支持中断,但是这种方法会使您的代码不可移植,并且可能在任何方面都不会更干净。

评论

0赞 curiousguy 1/19/2020
中断与高级 C++ 线程相对应的 linux“进程”将停止使用 CPU,但它永远无法解除分配其他资源或将内部数据结构恢复到以前的状态,甚至无法恢复到任何一致的状态,如果它们正在被修改,或解除互斥锁等。
43赞 Matthieu M. 12/15/2012 #2

@bamboon的回答很好,但我觉得这值得一个更有力的声明。

无论您使用哪种语言,您的程序都将获取和释放资源:内存、文件描述符......对于一次性启动的简单程序,泄漏资源并不重要:当程序结束时,现代操作系统会自动收回资源;但是,对于长时间运行的程序,基本要求是不要泄漏资源,或者至少不要重复。

因此,您应该从一开始就被教导,当您获得资源时,您必须确保它在某一时刻被释放:

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

    /* do something */

    free(array);
}

所以,问自己一个问题:

  • 当我杀死程序时会发生什么?
  • 当我杀死线程时会发生什么?

好吧,正如我们所说,当一个程序结束时,操作系统会收集资源,所以假设(这是一些假设)你没有在另一个系统上获得资源,或者这个系统得到了很好的保护,免受这种滥用,没有伤害,没有犯规。

但是,当您终止线程时,程序仍会运行,因此操作系统不会重新收集资源。你泄漏了内存,你锁定了一个你无法再解锁的文件进行写入,......你不应该杀死线程

高级语言有一种方法可以处理这个问题:异常。因为程序无论如何都应该是异常安全的,所以 Java(例如)会通过暂停线程来终止线程,在执行点抛出异常,然后轻轻地展开堆栈。但是,C++中还没有这样的设施。

不可能吗?不,显然不是。实际上,您可以完美地重用相同的想法:

  • encapsulate ,class 还将包含一个中断标志std::threadinterruptible_thread
  • 在启动标志时将标志的地址传递给它,并以线程本地的方式存储它std::thread
  • 使用检查点检测代码,检查是否设置了中断标志,以及何时引发异常

那是:

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

现在,您可以在适当的位置对线程代码进行中断检查。

评论

7赞 Brett Hale 12/15/2012
+1,这是一个如此重要的概念。线程与进程位于不同的资源和安全域中。他们需要一种合作而不是“对抗”的方法。重构代码,以便线程可以在请求时正常终止。
1赞 Jonathan Wakely 12/16/2012
void foo(int)已经不是例外安全了,如果你在“/* 做某事 */”中间有一个中断检查,它仍然是错误的。
2赞 Matthieu M. 12/16/2012
@JonathanWakely:对不起,误读了。我的观点是,异常是语言中的一种正常机制,因此你可以用正常的方式来满足它们:块、RAII 等......而残酷的中断让你没有清理的工具。请注意,我说过适当的地方检查中断。!而且你仍然可以打断 foo,只要你抓住异常来执行......但这并不是真的那样,我更明确地炫耀清理的必要性,而一个精心构建的 C++ 程序显然会使用 RAII。try/catchfree
1赞 Nanno Langstraat 12/12/2013
请注意,boost::thread 的功能使用了大致相似的方法。他们的术语:“中断点”。boost::thread 与上述代码相比的一个优势是:boost::thread 还内置了对睡眠操作中断的支持。例如 boost::thread::sleep_for()。terminate()
1赞 Simon 3/22/2014
并不总是可以以这种方式终止线程。如果它执行一些阻塞 io,比如调用 .并且没有标准的方法可以以非阻塞的方式做到这一点。getline