使用pthread_cancel取消线程:好做法还是坏做法 我在Linux上有一个C++程序(CCENTS 5.3),它生成多个线程,它们在无限循环中执行一个任务,并在某些分钟内休眠。 现在,我必须取消正在运行的线程,以防出现新的配置通知,并新启动一组线程,我使用了pthread_cancel。 我观察到的是,即使在接收到取消指示后,线程也没有停止,甚至在睡眠完成后,一些睡眠线程也出现了
由于该行为不是所需的,在上述场景中使用pthread_cancel会引起关于是好的还是坏的实践的问题使用pthread_cancel取消线程:好做法还是坏做法 我在Linux上有一个C++程序(CCENTS 5.3),它生成多个线程,它们在无限循环中执行一个任务,并在某些分钟内休眠。 现在,我必须取消正在运行的线程,以防出现新的配置通知,并新启动一组线程,我使用了pthread_cancel。 我观察到的是,即使在接收到取消指示后,线程也没有停止,甚至在睡眠完成后,一些睡眠线程也出现了,c++,linux,pthreads,C++,Linux,Pthreads,由于该行为不是所需的,在上述场景中使用pthread_cancel会引起关于是好的还是坏的实践的问题 请评论上述场景中pthread_cancel的用法。一般来说,线程取消并不是一个好主意。如果可能的话,最好有一个共享标志,线程使用它来中断循环。这样,您就可以让线程在实际退出之前执行它们可能需要执行的任何清理 在线程没有实际取消的问题上,POSIX规范确定了一组取消点()。只能在这些点取消线程。如果无限循环不包含取消点,可以通过调用pthread\u testcancel添加一个取消点。如果调用
请评论上述场景中pthread_cancel的用法。一般来说,线程取消并不是一个好主意。如果可能的话,最好有一个共享标志,线程使用它来中断循环。这样,您就可以让线程在实际退出之前执行它们可能需要执行的任何清理
在线程没有实际取消的问题上,POSIX规范确定了一组取消点()。只能在这些点取消线程。如果无限循环不包含取消点,可以通过调用
pthread\u testcancel
添加一个取消点。如果调用了代码> pthRead取消/<代码>,那么它将在此时生效。 如果您编写的异常安全C++代码(参见)比您的代码自然准备好了线程取消。这样您的析构函数就可以进行适当的清理。我会使用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 );
}
#包括
#包括
#包括
...
无效*控制(无效*pparam)
{
尝试
{
//在这里做你的工作,也许是长循环
}
捕获(abi::\u强制\u释放&)
{//handle pthread\u取消堆栈展开异常
投掷;
}
捕获(例外和例外)
{
掷骰子;
}
}
int main()
{
pthread_t tid;
int rtn;
rtn=pthread_create(&tid,NULL,Control,NULL);
美国LEEP(500);
//这里还有其他工作吗
rtn=pthtead\U cancel(tid);
}
+1为了避免取消,这是最快的内存泄漏方法,甚至更糟。礼貌地问:)似乎我必须使用共享标志更改线程终止的逻辑。但另一方面,我的程序将取消状态的线程设置为异步,我相信这与调用相应的清理处理程序后立即终止线程有关。@user584631:pthreads手册页上说,当模式设置为异步时,可以立即取消,但是系统不需要这样做。系统不需要立即取消线程,直到线程执行仍然不知道取消,是吗?不同意pthread\u cancel()
可能更易于使用。如果调用pthread\u cleanup\u push()
和pthread\u cleanup\u pop()
来设置清理处理程序,则可以避免资源泄漏。如果OP知道它们永远不需要在另一个pthreads实现上运行,这没关系,但我建议不要依赖通过异常实现的线程取消。使用标志将线程退出“隐藏内容”的领域,并进入您可以看到的代码中,使以后的维护人员更容易操作。我对这个问题已经有多年的经验,我认为最好的办法是避免取消,因为当你在组合中有取消时,总会有一些事情让你绊倒。这篇博客文章描述了为什么RAII不能与取消组合:@erenon很好的文章,但这只是故事的一半。“可以在析构函数中禁用线程取消功能。”MaximEgorushkin对一个5年前的问题发表了很晚的评论,但我喜欢你的想法。我可以用GCC指定所有的C++ DeStruts应该自动地(暂时)禁用pthRead取消吗?@ EikalAP。