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

64jmpszr  于 2023-04-19  发布在  其他
关注(0)|答案(7)|浏览(412)

在我的析构函数中,我想干净地销毁一个线程。
我的目标是等待一个线程完成执行,然后销毁该线程。
关于查询pthread的状态,我发现的唯一一件事是pthread_attr_setdetachstate,但这只告诉你你的线程是否是:

  • PTHREAD_CREATE_DETACHED
  • PTHREAD_创建_可连接

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

如何查询pthread是否还在运行

bwntbbo3

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。这允许两个线程一致地访问相同的数据,而不需要同步构造(互斥锁/信号量)。

czq61nw1

czq61nw12#

pthread_kill(tid, 0);

不发送信号,但仍执行错误检查,因此您可以使用它来检查tid是否存在。

注意事项:这个答案是不正确的。标准明确禁止传递生命周期已经结束的线程的ID。该ID现在可能指定不同的线程,或者更糟的是,它可能引用已释放的内存,从而导致崩溃。

a64a0gku

a64a0gku3#

我认为你真正需要的是调用pthread_join()。这个调用在线程退出之前不会返回。
如果只想轮询线程是否仍在运行(注意,这通常不是你想要做的!),你可以让线程在退出之前设置一个volatile boolean为false...然后你的主线程可以读取布尔值,如果它仍然为true,你知道线程仍然在运行。(如果它是假的,另一方面,你知道线程至少几乎消失了;但是,它可能仍然在运行在将布尔值设置为false之后发生的清理代码,因此即使在这种情况下,您仍然应该在尝试释放线程可能访问的任何资源之前调用pthread_join)

4ktjp1zp

4ktjp1zp4#

没有完全可移植的解决方案,看看你的平台是否支持pthread_tryjoin_np或pthread_timedjoin_np。所以你只需要检查线程是否可以被连接(当然是用PTHREAD_CREATE_JOINABLE创建的)。

2cmtqfgy

2cmtqfgy5#

让我注意一下“获胜”的答案,它有一个巨大的隐藏缺陷,在某些情况下它可能导致崩溃。除非你使用pthread_join,否则它会一次又一次地出现。假设你有一个进程和一个共享库。调用库lib.so。
1.你打开它,你在它里面开始一个线程。假设你不想让它连接到它,所以你设置它是可分离的。
1.进程和共享库的逻辑正在工作,等等。
1.您想加载lib.so,因为您不再需要它了。
1.你在线程上调用关闭,然后说,你想在之后从lib.so的线程中读取一个标志,它已经完成了。
1.您继续使用dlclose处理另一个线程,因为您看到,您已经看到,标志现在显示线程为“finished”

  1. dlclose将加载所有堆栈和代码相关的内存。
    1.哇,但是dlclose并不会停止线程。而且你知道,即使你在清理处理程序的最后一行设置了“线程结束”volatile原子标志变量,你仍然需要从堆栈上的很多方法中返回,返回值等。如果给#5+#6的线程一个巨大的线程优先级,你会收到dlclose之前,你可以真正停止在线程。你会有一些不错的崩溃,有时。
    让我指出,这不是一个hipothetical问题,我有同样的问题,我们的项目。
wecizke3

wecizke36#

我相信我已经提出了一个解决方案,至少在Linux上是可行的,每当我创建一个线程时,我都保存它的LWP(轻量级进程ID)并给它分配一个唯一的名称,例如:intlwp = syscall(SYS_gettid);prctl(PR_SET_NAME,(long)“unique name”,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);
}
1cklez4t

1cklez4t7#

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

相关问题