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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2156353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 04:18:12  来源:igfitidea点击:

How do you query a pthread to see if it is still running?

cmultithreadingconcurrencypthreadsdestructor

提问by Trevor Boyd Smith

In my destructor I want to destroy a thread cleanly.

在我的析构函数中,我想干净地销毁一个线程。

My goal is to wait for a thread to finish executing and THEN destroy the thread.

我的目标是等待一个线程完成执行,然后销毁该线程。

The only thing I found about querying the state of a pthread is pthread_attr_setdetachstatebut this only tells you if your thread is:

我发现查询 pthread 状态的唯一方法是pthread_attr_setdetachstate但这只会告诉您您的线程是否为:

  • PTHREAD_CREATE_DETACHED
  • PTHREAD_CREATE_JOINABLE
  • PTHREAD_CREATE_DETACHED
  • PTHREAD_CREATE_JOINABLE

Both of those have nothing to do with whether the thread is still running or not.

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

How do you query a pthread to see if it is still running?

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

采纳答案by jeremytrimble

It sounds like you have two questions here:

听起来您在这里有两个问题:

How can I wait until my thread completes?

我怎样才能等到我的线程完成?

Answer: This is directly supported by pthreads -- make your thread-to-be-stopped JOINABLE (when it is first started), and use pthread_join() to block your current thread until the thread-to-be-stopped is no longer running.

答:这是pthreads直接支持的——让你的待停止线程JOINABLE(当它第一次启动时),并使用pthread_join()阻塞你当前的线程,直到待停止线程不再跑步。



How can I tell if my thread is still running?

如何判断我的线程是否仍在运行?

Answer: You can add a "thread_complete" flag to do the trick:

答:您可以添加一个“thread_complete”标志来实现这一点:

Scenario: Thread A wants to know if Thread B is still alive.

场景:线程 A 想知道线程 B 是否还活着。

When Thread B is created, it is given a pointer to the "thread_complete" flag address. The "thread_complete" flag should be initialized to NOT_COMPLETED before the thread is created. Thread B's entry point function should immediately call pthread_cleanup_push() to push a "cleanup handler" which sets the "thread_complete" flag to COMPLETED.

当创建线程 B 时,它被赋予一个指向“thread_complete”标志地址的指针。在创建线程之前,“thread_complete”标志应该被初始化为 NOT_COMPLETED。线程 B 的入口点函数应立即调用 pthread_cleanup_push() 以推送“清理处理程序”,该处理程序将“thread_complete”标志设置为 COMPLETED。

See details about cleanup handlers here: pthread cleanup handlers

在此处查看有关清理处理程序的详细信息:pthread 清理处理程序

You'll want to include a corresponding pthread_cleanup_pop(1) call to ensure that the cleanup handler gets called no matter what (i.e. if the thread exits normally OR due to cancellation, etc.).

您需要包含一个相应的 pthread_cleanup_pop(1) 调用,以确保无论如何都会调用清理处理程序(即,如果线程正常退出或由于取消等原因)。

Then, Thread A can simply check the "thread_complete" flag to see if Thread B has exited yet.

然后,线程 A 可以简单地检查“thread_complete”标志以查看线程 B 是否已经退出。

NOTE: Your "thread_complete" flag should be declared "volatile" and should be an atomic type -- the GNU compilers provide the sig_atomic_t for this purpose. This allows the two threads consistent access the same data without the need for synchronization constructs (mutexes/semaphores).

注意:你的“thread_complete”标志应该被声明为“volatile”并且应该是一个原子类型——GNU编译器为此目的提供了sig_atomic_t。这允许两个线程一致地访问相同的数据,而无需同步构造(互斥体/信号量)。

回答by pthread_kill

pthread_kill(tid, 0);

No signal is sent, but error checking is still performed so you can use that to check existence of tid.

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

CAUTION: This answer is incorrect. The standard specifically prohibits passing the ID of a thread whose lifetime has ended. That ID might now specify a different thread or, worse, it might refer to memory that has been freed, causing a crash.

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

回答by Jeremy Friesner

I think all you really need is to call pthread_join(). That call won't return until the thread has exited.

我认为您真正需要的只是调用 pthread_join()。在线程退出之前,该调用不会返回。

If you only want to poll to see whether the thread is still running or not (and note that is usually not what you should be wanting to do!), you could have the thread set a volatile boolean to false just before it exits... then your main-thread could read the boolean and if it's still true, you know the thread is still running. (if it's false, on the other hand, you know the thread is at least almost gone; it may still be running cleanup code that occurs after it sets the boolean to false, though, so even in this case you should still call pthread_join before trying to free any resources the thread might have access to)

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

回答by Dewfy

There is not fully portable solution, look if your platform supports pthread_tryjoin_np or pthread_timedjoin_np. So you just check if thread can be joined (of course created with PTHREAD_CREATE_JOINABLE).

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

回答by Priyesh Shah Pilu

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

回答by newhouse

Let me note on the "winning" answer, which has a huge hidden flaw, and in some contexts it can lead to crashes. Unless you use pthread_join, it will coming up again and again. Assume you are having a process and a shared library. Call the library lib.so.

让我注意“获胜”答案,它有一个巨大的隐藏缺陷,在某些情况下它可能导致崩溃。除非你使用 pthread_join,否​​则它会一次又一次地出现。假设您有一个进程和一个共享库。调用库 lib.so。

  1. You dlopen it, you start a thread in it. Assume you don't want it join to it, so you set it detachable.
  2. Process and shared lib's logic doing its work, etc...
  3. You want to load out lib.so, because you don't need it any more.
  4. You call a shutdown on the thread and you say, that you want to read a flag afterwards from your lib.so's thread, that it have finished.
  5. You continue on another thread with dlclose, because you see, that you have saw, that the flag is now showing the thread as "finished"
  6. dlclose will load out all stack and code related memory.
  7. Whops, but dlclose does not stop threads. And you know, even when you are in the last line of the cleanup handler to set the "thread is finished" volatile atomic flag variable, you still have to return from a lot of methods on the stack, giving back values, etc. If a huge thread priority was given to #5+#6's thread, you will receive dlclose before you could REALLY stop on the thread. You will have some nice crashes sometimes.
  1. 你打开它,你在里面开始一个线程。假设您不希望它加入它,因此您将其设置为可拆卸。
  2. 处理和共享库的逻辑执行其工作等...
  3. 您想加载 lib.so,因为您不再需要它了。
  4. 您在线程上调用关闭并说,您想之后从 lib.so 的线程中读取一个标志,它已经完成。
  5. 您继续使用 dlclose 处理另一个线程,因为您看到,您已经看到,标志现在将线程显示为“已完成”
  6. dlclose 将加载所有堆栈和代码相关的内存。
  7. 哎呀,但是 dlclose 不会停止线程。而且您知道,即使您在清理处理程序的最后一行设置“线程已完成”易失性原子标志变量,您仍然必须从堆栈上的许多方法返回,返回值等。如果#5+#6 的线程获得了巨大的线程优先级,在您真正停止线程之前,您将收到 dlclose。有时你会遇到一些不错的崩溃。

Let me point out, that this is not a hipothetical problem, I had the same issue on our project.

让我指出,这不是一个假设问题,我在我们的项目中遇到了同样的问题。

回答by Eric Buell

I believe I've come up with a solution that at least works for Linux. Whenever I create a thread I have it save it's LWP (Light Weight Process ID) and assign it a unique name, eg. int lwp = syscall(SYS_gettid); prctl(PR_SET_NAME, (long)"unique name", 0, 0, 0);

我相信我已经提出了一个至少适用于 Linux 的解决方案。每当我创建一个线程时,我都会保存它的 LWP(轻量级进程 ID)并为其分配一个唯一的名称,例如。int lwp = 系统调用(SYS_gettid);prctl(PR_SET_NAME, (long)"唯一名称", 0, 0, 0);

Then, to check if the thread exists later I open /proc/pid/task/lwp/comm and read it. If the file exists and it's contents match the unique name I assigned, the thread exists. Note that this does NOT pass a possibly defunct/reused TID to any library function, so no crashes.

然后,为了稍后检查线程是否存在,我打开 /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] = '##代码##';

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