使用pthread_cancel取消线程:好的做法或不好的

我在Linux上有一个C ++程序(CentOS 5.3)产生多个线程,在无限循环中执行一个任务并在一定的时间内hibernate。 现在,我必须取消正在运行的线程,以防万一发生新的configuration通知,并且新启动一组新的线程,为此我使用了pthread_cancel。 我观察到的是,即使接收到取消指示,线程也没有停止,甚至一些睡眠线程在睡眠完成后出现。

由于行为并不理想,所以在上述情况下使用pthread_cancel会引起对做法的好坏的质疑。

请在上述场景中对pthread_cancel用法进行评论。

一般来说,线程取消并不是一个好主意。 只要有可能,最好是有一个共享标志,这个标志被线程用来跳出循环。 这样,你将让线程执行任何清理,他们可能需要做的实际退出之前。

在线程没有实际取消的问题上,POSIX规范确定了一组取消点( man 7 pthreads )。 线程只能在这些点上取消。 如果您的无限循环不包含取消点,则可以通过调用pthread_testcancel来添加取消点。 如果pthread_cancel已被调用,那么它将在这一点上起作用。

如果您正在编写exception安全的C ++代码(请参阅http://www.boost.org/community/exception_safety.html ),那么您的代码自然就可以取消线程了。 glibs在线程取消时抛出C ++exception ,这样你的析构函数可以做适当的清理工作。

我会使用boost :: asio。

就像是:

 struct Wait { Wait() : timer_(io_service_), run_(true) {} boost::asio::io_service io_service_; mutable boost::asio::deadline_timer timer_; bool run_; }; void Wait::doWwork() { while (run) { boost::system::error_code ec; timer_.wait(ec); io_service_.run(); if (ec) { if (ec == boost::asio::error::operation_aborted) { // cleanup } else { // Something else, possibly nasty, happened } } } } void Wait::halt() { run_ = false; timer_.cancel(); } 

一旦你了解了它,asio是一个很棒的工具。

你可以做相当于下面的代码。

 #include <pthread.h> #include <cxxabi.h> #include <unistd.h> ... void *Control(void* pparam) { try { // do your work here, maybe long loop } catch (abi::__forced_unwind&) { // handle pthread_cancel stack unwinding exception throw; } catch (exception &ex) { throw ex; } } int main() { pthread_t tid; int rtn; rtn = pthread_create( &tid, NULL, Control, NULL ); usleep(500); // some other work here rtn = pthtead_cancel( tid ); }