你如何查询pthread以查看它是否仍在运行?

时间:2010-01-28 17:01:59

标签: c multithreading concurrency pthreads destructor

在我的析构函数中,我想彻底销毁一个线程。

我的目标是等待线程完成执行然后破坏线程。

我发现有关查询pthread状态的唯一事情是pthread_attr_setdetachstate,但这只会告诉您线程是否为:

  • PTHREAD_CREATE_DETACHED
  • PTHREAD_CREATE_JOINABLE

这两个都与线程是否仍在运行无关。

如何查询pthread以查看它是否仍在运行?

7 个答案:

答案 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。

  1. 你打开它,你开始一个线程。假设你不希望它加入它,所以你可以将它设置为可拆卸。
  2. 处理和共享lib的逻辑正在进行其工作等......
  3. 您想要加载lib.so,因为您不再需要它。
  4. 你在线程上调用了一个关闭,你说,你想从你的lib.so的线程中读取一个标志,它已经完成了。
  5. 你继续使用dlclose的另一个线程,因为你看到,你已经看到,该标志现在显示线程为"已完成"
  6. dlclose将加载所有堆栈和代码相关的内存。
  7. Whops,但dlclose不会停止线程。而且你知道,即使你在清理处理程序的最后一行设置"线程已经完成" volatile原子标志变量,你仍然必须从堆栈上的很多方法返回,返回值等。如果给#5 +#6&#39的线程一个巨大的线程优先级,你将在你之前收到dlclose可能真的停在线程上。你有时候会遇到一些很好的崩溃。
  8. 让我指出,这不是一个解决问题的问题,我在项目中遇到了同样的问题。

答案 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");
}