在我的析构函数中,我想干净地销毁一个线程。
我的目标是等待一个线程完成执行,然后销毁该线程。
关于查询pthread的状态,我发现的唯一一件事是pthread_attr_setdetachstate,但这只告诉你你的线程是否是:
- PTHREAD_CREATE_DETACHED
- PTHREAD_创建_可连接
这两个都与线程是否仍在运行无关。
如何查询pthread是否还在运行
在我的析构函数中,我想干净地销毁一个线程。
我的目标是等待一个线程完成执行,然后销毁该线程。
关于查询pthread的状态,我发现的唯一一件事是pthread_attr_setdetachstate,但这只告诉你你的线程是否是:
这两个都与线程是否仍在运行无关。
如何查询pthread是否还在运行
7条答案
按热度按时间bwntbbo31#
听起来你有两个问题:
如何等待线程完成?
答:这是pthreads直接支持的--让你的要停止的线程JOINABLE(当它第一次启动时),并使用pthread_join()来阻止你的当前线程,直到要停止的线程不再运行。
如何判断线程是否还在运行?
答:你可以添加一个“thread_complete”标志来完成这个任务:
场景:线程A想知道线程B是否还活着。
当线程B被创建时,它被赋予一个指向“thread_complete”标志地址的指针。在线程被创建之前,“thread_complete”标志应该被初始化为NOT_COMPLETED。线程B的入口点函数应该立即调用pthread_cleanup_push()来推送一个“cleanup handler”,该“cleanup handler”将“thread_complete”标志设置为COMPLETED。
有关清理处理程序的详细信息,请参阅此处:pthread cleanup handlers
您需要包含一个相应的pthread_cleanup_pop(1)调用,以确保无论发生什么情况(即,如果线程正常退出或由于取消等原因退出),都会调用清理处理程序。
然后,线程A可以简单地检查“thread_complete”标志以查看线程B是否已经退出。
注意:你的“thread_complete”标志应该声明为“volatile”,并且应该是一个原子类型--GNU编译器为此提供了sig_atomic_t。这允许两个线程一致地访问相同的数据,而不需要同步构造(互斥锁/信号量)。
czq61nw12#
不发送信号,但仍执行错误检查,因此您可以使用它来检查tid是否存在。
注意事项:这个答案是不正确的。标准明确禁止传递生命周期已经结束的线程的ID。该ID现在可能指定不同的线程,或者更糟的是,它可能引用已释放的内存,从而导致崩溃。
a64a0gku3#
我认为你真正需要的是调用pthread_join()。这个调用在线程退出之前不会返回。
如果只想轮询线程是否仍在运行(注意,这通常不是你想要做的!),你可以让线程在退出之前设置一个volatile boolean为false...然后你的主线程可以读取布尔值,如果它仍然为true,你知道线程仍然在运行。(如果它是假的,另一方面,你知道线程至少几乎消失了;但是,它可能仍然在运行在将布尔值设置为false之后发生的清理代码,因此即使在这种情况下,您仍然应该在尝试释放线程可能访问的任何资源之前调用pthread_join)
4ktjp1zp4#
没有完全可移植的解决方案,看看你的平台是否支持pthread_tryjoin_np或pthread_timedjoin_np。所以你只需要检查线程是否可以被连接(当然是用PTHREAD_CREATE_JOINABLE创建的)。
2cmtqfgy5#
让我注意一下“获胜”的答案,它有一个巨大的隐藏缺陷,在某些情况下它可能导致崩溃。除非你使用pthread_join,否则它会一次又一次地出现。假设你有一个进程和一个共享库。调用库lib.so。
1.你打开它,你在它里面开始一个线程。假设你不想让它连接到它,所以你设置它是可分离的。
1.进程和共享库的逻辑正在工作,等等。
1.您想加载lib.so,因为您不再需要它了。
1.你在线程上调用关闭,然后说,你想在之后从lib.so的线程中读取一个标志,它已经完成了。
1.您继续使用dlclose处理另一个线程,因为您看到,您已经看到,标志现在显示线程为“finished”
1.哇,但是dlclose并不会停止线程。而且你知道,即使你在清理处理程序的最后一行设置了“线程结束”volatile原子标志变量,你仍然需要从堆栈上的很多方法中返回,返回值等。如果给#5+#6的线程一个巨大的线程优先级,你会收到dlclose之前,你可以真正停止在线程。你会有一些不错的崩溃,有时。
让我指出,这不是一个hipothetical问题,我有同样的问题,我们的项目。
wecizke36#
我相信我已经提出了一个解决方案,至少在Linux上是可行的,每当我创建一个线程时,我都保存它的LWP(轻量级进程ID)并给它分配一个唯一的名称,例如:intlwp = syscall(SYS_gettid);prctl(PR_SET_NAME,(long)“unique name”,0,0,0);
然后,为了检查线程是否存在,我打开/proc/pid/task/lwp/comm并读取它。如果文件存在并且它的内容与我分配的唯一名称匹配,则线程存在。注意,这不会将可能失效/重用的TID传递给任何库函数,因此不会崩溃。
1cklez4t7#