C : pthread dataspecific 析构函数只调用一次

cla*_*laf 5 c destructor pthreads

pthread_key_create联机帮助页:

一个可选的析构函数可以与每个键值相关联。在线程退出时,如果键值具有非 NULL 析构函数指针,并且线程具有与键关联的非 NULL 值,则使用当前关联值作为其唯一参数调用指向的函数。如果一个线程退出时存在多个析构函数,则析构函数调用的顺序是不确定的。

如果在为所有具有关联析构函数的非 NULL 值调用了所有析构函数之后,仍有一些具有关联析构函数的非 NULL 值,则重复该过程。如果在至少 [PTHREAD_DESTRUCTOR_ITERATIONS] 次迭代析构函数调用未完成的非 NULL 值之后,仍然有一些非 NULL 值与关联的析构函数,则实现将停止调用析构函数。

我写了一个小例子,用一个简单的析构函数为非空线程特定值打印“Hello World”。据我所知,即使在第一次调用析构函数后线程特定值仍然不是 NULL,这个析构函数也只被调用一次(至少在 linux fedora 和 mac os x 上)。

我错过了什么吗?!(在 glibc 上 PTHREAD_DESTRUCTOR_ITERATIONS = 4。)

这是我的小例子:

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

#define NB_THREADS 1
#define NB_KEYS 1

static pthread_key_t keys[NB_KEYS];
static pthread_mutex_t mutex;

void destruction (void *arg)
{
  (int) arg ++;
  printf ("Destructor called! -- key value : %i\n", (int)arg);
}

void* startup_routine(void* argv)
{
  int i;
  int th = (int) argv;

  for (i = 0; i < NB_KEYS; i++)
    pthread_setspecific(keys[i], (void*) ((th + i)* 2));

  pthread_mutex_lock(&mutex);

  printf("Thread %i\n", th);

  for (i = 0; i < NB_KEYS; i++)
    printf ("\tkeys[%i] : %i\n", i, (int)pthread_getspecific(keys[i]));

  pthread_mutex_unlock(&mutex);

  return "End";
}

int main(int argc, char** argv)
{
  int i;
  void *result;
  pthread_t thread[NB_THREADS];

  for (i = 0; i < NB_KEYS; i++)
    pthread_key_create(&keys[i], destruction);

  pthread_mutex_init(&mutex, NULL);

  for (i = 0; i < NB_THREADS; i++)
    pthread_create( &thread[i], NULL, startup_routine, (void*)(i+1) );

  for (i = 0; i < NB_THREADS; i++)
  {
    pthread_join( thread[i], &result );
    printf("Return from the thread %i = '%s'\n", i, (char*)result );
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

cla*_*laf 4

看来这里使用 pthread 的人不多!

因此,我将再次回答我自己的问题:

仅当在析构函数中调用时,析构函数才会被调用多次pthread_setspecific,从而更改键的值。

这是因为在调用析构函数之前,键指针被设置为空,并将指针传递给析构函数。因此,如果我们希望键指针不为空,只需pthread_setspecific在其中调用即可。

  • 正确的。如果只有一个键值要析构,则析构函数仅被调用一次。假设析构函数实际上销毁了该对象。析构函数可能被多次调用的原因是另一个析构函数的操作可能会重新创建该值。 (2认同)