【问题标题】:pthread_key_create() - When does the `destructor` function invoked?pthread_key_create() - 什么时候调用“析构函数”?
【发布时间】:2015-09-23 12:55:18
【问题描述】:

我编写了一个程序来了解 Linux (Linux 3.13.0-24-generic #46-Ubuntu) 上的线程特定数据,如下所示。

我尝试在传递给pthread_key_create()的析构函数中打印线程id,但似乎只有子线程成功打印,而主线程没有打印该信息。

我的问题是:

析构函数是在线程终止之前还是之后调用?

主线程没有打印信息,是不是因为主线程已经被销毁了?

tsd_test.c

// test of thread-specific data

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>

static pthread_once_t once = PTHREAD_ONCE_INIT;
static pthread_key_t tidKey;

static void destructor(void *buf) {
    unsigned long *_tid = buf;
    printf("destroy, tid: %lu\n", *_tid);
    free(buf);
}

static void createKey(void) {
    int s = pthread_key_create(&tidKey, destructor);
    if(s != 0) {
        printf("failed to create key\n");
        exit(-1);
    }
}

void *store_tid() {
    int s;
    unsigned long *buf;

    // create key
    s = pthread_once(&once, createKey);
    if(s != 0) {
        printf("failed to create key\n");
        exit(-1);
    }

    buf = pthread_getspecific(tidKey);
    if(buf == NULL) { // thread call this function for the first time,
        buf = malloc(sizeof(unsigned long));
        if(buf == NULL) {
            printf("failed to allocate memory, %s\n", strerror(errno));
            exit(-1);
        }
        // register buffer to specified key & current thread,
        s = pthread_setspecific(tidKey, buf);
        if(s != 0) {
            printf("failed to setspecific\n");
            exit(-1);
        }
    }

    // store tid to buffer,
    *buf = (unsigned long)pthread_self();
    printf("set tid to: %lu\n", *buf);

    return buf;
}

void tsd_test() {
    unsigned long *tidp_a = store_tid();
    printf("tid - before call another thread: %lu\n", *tidp_a);

    int s;
    pthread_t t2;
    s = pthread_create(&t2, NULL, &store_tid, NULL);
    if(s != 0) {
        printf("failed to create thread\n");
        exit(-1);
    }

    s = pthread_join(t2, NULL);
    if(s != 0) {
        printf("failed to join thread\n");
        exit(-1);
    }

    printf("tid - after call another thread: %lu\n", *tidp_a);
}

int main(int argc, char *argv[]) {
    tsd_test();
    return 0;
}

编译:

gcc -pthread tsd_test.c

输出:

set tid to: 3076318976
tid - before call another thread: 3076318976
set tid to: 3076315968
destroy, tid: 3076315968
tid - after call another thread: 3076318976

可以看到只有子线程打印“destroy”,而主线程没有。

【问题讨论】:

  • OT:pthread函数需要的签名是void*(*)(void*),所以应该是void *store_tid(void*)。编译所有警告(-Wall -Wextra -pedantic for gcc)以获得此类问题的通知。
  • @alk 明白了,很好的提示。

标签: c linux multithreading pthreads


【解决方案1】:

线程析构函数是在线程退出时调用的,而不是在进程终止时调用,即当main() 退出时,整个进程都会终止。所以不会调用析构函数。

main() 函数的末尾或tst() 函数的末尾调用pthread_exit(NULL);(两者确实相同)。现在,您将看到正在调用的析构函数。

【讨论】:

  • 我想知道为什么pthread_exit() 会有所作为?它是在终止线程之前调用destructor,还是...?
  • 从 pthread_create() 创建的线程返回或调用 pthread_exit(); 将隐式调用析构函数(如果有)。但是从 main() 返回或退出是不行的,它会退出整个过程。 pthread_exit() 上的 POSIX 表示 在执行了所有取消清除处理程序之后,如果线程有任何线程特定的数据,则会以未指定的顺序调用适当的析构函数。
  • 我在手册页看到,我猜它会先调用destructor,然后触发线程终止,无论是主线程还是子线程。
  • 没有。从 main() 线程返回(相当于调用exit())与从另一个线程返回(相当于调用pthread_exit())不同。
  • 我的意思是,如果使用 pthread_exit(),那么 pthread_exit() 将在终止线程之前首先调用析构函数。我不确定这是不是真的,但这似乎是合理的。
猜你喜欢
  • 2019-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 2020-11-05
  • 2018-05-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多