C ++ 0x线程中断
根据C ++ 0x最终草案,没有办法请求线程终止。 这就是说,如果需要,我们需要实施一个自己动手的解决scheme。
另一方面,boost :: thread提供了一种以安全方式中断线程的机制。
在你看来,最好的解决scheme是什么? devise自己的合作“中断机制”还是本土化?
所有的语言规范都表示,这种支持不是内置于语言中的。 boost::thread::interrupt
需要线程函数的一些支持:
当被中断的线程接下来执行一个指定的中断点时(或者如果它正在执行一个被阻塞的话)
即当线程函数不给调用者一个中断的机会时,你仍然卡住。
我不确定你的意思是“本土化” – 没有本地支持,除非你拼命地boost:threads
。
不过,我会使用一个明确的机制。 无论如何,你必须考虑有足够的中断点,为什么不明确? 根据我的经验,额外的代码通常是微不足道的,尽pipe您可能需要将一些等待从单个对象更改为多个对象,这取决于您的库,可能看起来更丑陋。
人们也可以把“不要使用控制stream程的exception”,但是与线程混淆,这只是一个指导。
使用本地句柄来取消线程在C ++中是一个不好的select,因为你需要销毁所有的堆栈分配对象。 这是他们不包括取消操作的主要原因。
Boost.Thread提供了一个中断机制,需要在任何等待原语上进行池化。 由于这个通用机制可能是昂贵的,所以标准没有包括在内。
你将需要自己实现它。 看到我的答案在这里如何自己实现这个类似的问题。 为了完成解决scheme,当中断为真并且线程应该捕获这个中断并且完成时,应该抛出中断。
它终止一个线程是不安全的,因为你不能控制当时正在处理的任何数据结构的状态。
如果你想中断正在运行的线程,你必须实现你自己的机制。 恕我直言,如果你需要,你的devise不准备多个线程。
如果你只是想等待一个线程完成,使用join()或未来。
实施一个自己动手的解决scheme是最有意义的,它确实不应该那么难。 您将需要一个共享的variables,您可以同步读取/写入,指示线程是否被要求终止,并且当线程处于可以安全中断的状态时,线程将周期性地读取该variables。 当你想要中断一个线程时,你只需要同步写入这个variables,然后你join这个线程。 假设它合适地合作,它应该注意到variables已经被写入和closures,导致连接function不再被阻塞。
如果你要去土生土长,那么你就不会有任何收获。 你只需要抛弃标准和跨平台的OOP线程机制的所有好处。 为了让你的代码正确,线程需要协作closures,这就意味着上述的通信。
抢先终止线程是不安全的,因为整个过程的状态在那个点之后变得不确定。 线程在被终止之前可能已经获得了关键部分。 那个关键部分现在永远不会被释放。 堆可能会永久locking,等等。
boost::thread::interrupt
解决scheme的工作方式很好。 它只会中断一个线程执行一些可以中断的事情,比如等待一个Boost.Thread条件variables,或者如果线程在中断被调用后执行了其中一个事件。 即使这样,这个线程也不会像Win32的TerminateThread
函数那样通过绞肉机,它只是引发一个exception,如果你已经是一个行为良好的编码器,并且在任何地方都使用RAII,本身和优雅地退出线程。
这是我谦卑的执行一个线程取消器(对于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; }
我的线程实现使用pimpl习语,而在Impl类中,我为每个支持的操作系统提供了一个版本,还有一个使用boost的版本,所以我可以决定在构build项目时使用哪一个版本。
我决定做两个类:一个是Thread,它只有基本的,OS提供的服务; 另一个是SafeThread,它inheritance了Thread,并具有协作中断的方法。
线程有一个终止()方法,做一个侵入性终止。 这是一个在SafeThread中重载的虚拟方法,在这里它发出一个事件对象的信号。 有一个(静态)yeld()方法,运行线程应该不时调用; 这个方法检查事件对象是否有信号,如果是的话,会引发一个在线程入口点的调用者处捕获的exception,从而终止线程。 当它这样做时,它会发出第二个事件对象的信号,所以terminate()的调用者可以知道线程已经安全停止了。
对于存在死锁风险的情况,SafeThread :: terminate()可以接受超时参数。 如果超时到期,它调用Thread :: terminate(),从而干扰线程。 当你有一些你无法控制的东西时(比如第三方API),或者在死锁比资源泄漏等更多的情况下,这是最后一个资源。
希望这对您的决定有用,并且会给我一个清晰的图片来说明我的deviseselect。 如果没有,我可以张贴代码片段来澄清,如果你想。
我同意这个决定。 例如,.NET允许中止任何工作线程,并且我从不使用此function,不build议对任何专业程序员这样做。 我想决定自己,当一个工作者的线程可能会中断,以及如何做到这一点。 它不同于硬件,I / O,UI和其他线程。 如果线程可能在任何地方停止,这可能导致资源pipe理,事务等的未定义的程序行为。