在我的析构函数中,我想彻底销毁一个线程。
我的目标是等待线程完成执行然后破坏线程。
我发现有关查询pthread状态的唯一事情是pthread_attr_setdetachstate,但这只会告诉您线程是否为:
这两个都与线程是否仍在运行无关。
如何查询pthread以查看它是否仍在运行?
答案 0 :(得分:38)
听起来你有两个问题:
答案:这是由pthreads直接支持的 - 让你的线程可以停止JOINABLE(首次启动时),并使用pthread_join()阻止当前线程,直到线程被停止不再运行了。
答案:您可以添加“thread_complete”标志来执行此操作:
场景:线程A想知道线程B是否还活着。
创建线程B时,会给它一个指向“thread_complete”标志地址的指针。在创建线程之前,应将“thread_complete”标志初始化为NOT_COMPLETED。线程B的入口点函数应该立即调用pthread_cleanup_push()来推送一个“清理处理程序”,它将“thread_complete”标志设置为COMPLETED。
在此处查看有关清理处理程序的详细信息:pthread cleanup handlers
你想要包含一个相应的pthread_cleanup_pop(1)调用,以确保无论如何调用清理处理程序(即如果线程正常退出或由于取消等)。
然后,线程A可以简单地检查“thread_complete”标志,看看线程B是否已经退出。
注意:您的“thread_complete”标志应声明为“volatile”并且应该是原子类型 - GNU编译器为此提供sig_atomic_t。这允许两个线程一致地访问相同的数据,而不需要同步构造(互斥/信号量)。
答案 1 :(得分:30)
pthread_kill(tid, 0);
没有信号发送,但仍然执行错误检查,因此您可以使用它进行检查 tid的存在。
注意:此答案不正确。该标准明确禁止传递其生命周期结束的线程的ID。该ID现在可能指定一个不同的线程,或者更糟糕的是,它可能引用已释放的内存,从而导致崩溃。
答案 2 :(得分:8)
我认为你真正需要的是调用pthread_join()。在线程退出之前,该调用不会返回。
如果你只想轮询以查看线程是否仍在运行(并注意通常不是你想要做的那样!),你可以让线程在它之前将volatile布尔值设置为false退出...然后你的主线程可以读取布尔值,如果它仍然是真的,你知道线程仍在运行。 (如果它是假的,另一方面,你知道线程至少几乎消失了;它可能仍在运行清除代码,它在布尔值设置为false之后发生,所以即使在这种情况下你仍然应该调用pthread_join之前试图释放线程可能有权访问的任何资源)
答案 3 :(得分:5)
没有完全可移植的解决方案,请查看您的平台是否支持pthread_tryjoin_np或pthread_timedjoin_np。所以你只需检查线程是否可以连接(当然是用PTHREAD_CREATE_JOINABLE创建的)。
答案 4 :(得分:0)
让我注意一下"中奖"答案,这有一个巨大的隐藏缺陷,在某些情况下,它可能导致崩溃。除非你使用pthread_join,它会一次又一次地出现。假设您正在拥有一个进程和一个共享库。调用库lib.so。
让我指出,这不是一个解决问题的问题,我在项目中遇到了同样的问题。
答案 5 :(得分:0)
我相信我已经提出了至少适用于Linux的解决方案。每当创建线程时,我都会保存它的LWP(轻量级进程ID)并为其分配一个唯一的名称,例如。 int lwp = syscall(SYS_gettid); prctl(PR_SET_NAME,(long)“唯一名称”,0,0,0);
然后,要稍后检查线程是否存在,我打开/ proc / pid / task / lwp / comm并阅读。如果该文件存在并且其内容与我分配的唯一名称匹配,则该线程存在。请注意,这不会将可能已失效/重用的TID传递给任何库函数,因此不会崩溃。
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <pthread.h>
#include <sys/prctl.h>
#include <sys/file.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <syscall.h>
pthread_t subthread_tid;
int subthread_lwp;
#define UNIQUE_NAME "unique name"
bool thread_exists (pthread_t thread_id)
{
char path[100];
char thread_name[16];
FILE *fp;
bool thread_exists = false;
// If the /proc/<pid>/task/<lwp>/comm file exists and it's contents match the "unique name" the
// thread exists, and it's the original thread (TID has NOT been reused).
sprintf(path, "/proc/%d/task/%d/comm", getpid(), subthread_lwp);
fp = fopen(path, "r");
if( fp != NULL ) {
fgets(thread_name, 16, fp);
fclose(fp);
// Need to trim off the newline
thread_name[strlen(thread_name)-1] = '\0';
if( strcmp(UNIQUE_NAME, thread_name) == 0 ) {
thread_exists = true;
}
}
if( thread_exists ) {
printf("thread exists\n");
} else {
printf("thread does NOT exist\n");
}
return thread_exists;
}
void *subthread (void *unused)
{
subthread_lwp = syscall(SYS_gettid);
prctl(PR_SET_NAME, (long)UNIQUE_NAME, 0, 0, 0);
sleep(10000);
return NULL;
}
int main (int argc, char *argv[], char *envp[])
{
int error_number;
pthread_create(&subthread_tid, NULL, subthread, NULL);
printf("pthread_create()\n");
sleep(1);
thread_exists(subthread_tid);
pthread_cancel(subthread_tid);
printf("pthread_cancel()\n");
sleep(1);
thread_exists(subthread_tid);
error_number = pthread_join(subthread_tid, NULL);
if( error_number == 0 ) {
printf("pthread_join() successful\n");
} else {
printf("pthread_join() failed, %d\n", error_number);
}
thread_exists(subthread_tid);
exit(0);
}
答案 6 :(得分:-1)
#include <string.h>
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
void* thread1 (void* arg);
void* thread2 (void* arg);
int main()
{
pthread_t thr_id;
pthread_create(&thr_id, NULL, thread1, NULL);
sleep(10);
}
void* thread1 (void* arg)
{
pthread_t thr_id = 0;
pthread_create(&thr_id, NULL, thread2, NULL);
sleep(5);
int ret = 0;
if( (ret = pthread_kill(thr_id, 0)) == 0)
{
printf("still running\n");
pthread_join(thr_id, NULL);
}
else
{
printf("RIP Thread = %d\n",ret);
}
}
void* thread2 (void* arg)
{
// sleep(5);
printf("I am done\n");
}