在 pthread 中使用条件变量而不是 join() 时检测到线程泄漏

Thread leak detected when using condition variable instead of join() with pthread

我是 pthread 同步的新手,在 google 中搜索“pthread 条件变量”并从 pdf 中获取示例:https://pages.cs.wisc.edu/~remzi/OSTEP/threads-cv.pdf .

示例代码如下,其目的是“使用条件变量和变量done实现pthread_join()”(据我理解):

// https://godbolt.org/z/8rPMq54K8
#include <stdio.h>
#include <pthread.h>

volatile int done  = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c  = PTHREAD_COND_INITIALIZER;
void thr_exit() {
    pthread_mutex_lock(&m);
    done = 1;
    pthread_cond_signal(&c);
    pthread_mutex_unlock(&m);
}
void *child(void *arg) {
    printf("child\n");
    thr_exit();
    return NULL;
}
void thr_join() {
    pthread_mutex_lock(&m);
    while (done == 0)
    {
        pthread_cond_wait(&c, &m);
    }
    pthread_mutex_unlock(&m);
}

int main(int argc, char *argv[])
{
    printf("parent: begin\n");
    pthread_t p;
    pthread_create(&p, NULL, child, NULL);
    thr_join();
    printf("parent: end\n");
    return 0;
}

编译:

clang++ main.cpp -fsanitize=thread -g -fno-omit-frame-pointer

运行 它将看到“线程泄漏”报告:

(base) ➜  case12 git:(main) ✗ ./a.out
a.out(71120,0x10433c580) malloc: nano zone abandoned due to inability to preallocate reserved vm space.
parent: begin
child
parent: end
==================
WARNING: ThreadSanitizer: thread leak (pid=71120)
  Thread T1 (tid=1365892, finished) created by main thread at:
    #0 pthread_create <null>:74364228 (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x2bbe8)
    #1 main main_v4.cpp:31 (a.out:arm64+0x100003e38)

SUMMARY: ThreadSanitizer: thread leak main_v4.cpp:31 in main
==================
ThreadSanitizer: reported 1 warnings

这段C++代码真的是线程泄漏,还是tsan的误报?

Is this C++ code really a thread leak, or just a false positive report from tsan?

这确实是一个线程泄漏,因为您无法实现 pthread_join() 的替代品。至少,不是以任何可移植的方式或仅基于 C++(或 C)和 pthreads 规范。该程序启动一个线程,在终止之前既不分离也不加入它。那是线程泄漏。

程序确实成功并可靠地等待终止,直到子线程提供它已调用 thr_exit() 的证据,但这不能代替加入子线程。

(这不是答案,只是我在阅读 John Bollinger 的答案后可以编写的解决方案代码。)

解决方案 1:

int main(int argc, char *argv[])
{
    printf("parent: begin\n");
    pthread_t p;
    pthread_create(&p, NULL, child, NULL);
    pthread_detach(p);  // !! new added line
    thr_join();
    printf("parent: end\n");
    return 0;
}

解决方案2:

void *child(void *arg) {
    pthread_detach(pthread_self()); //!! new added line
    printf("child\n");
    thr_exit();
    return NULL;
}