5
votes

From pthread_key_create manpage :

An optional destructor function may be associated with each key value. At thread exit, if a key value has a non-NULL destructor pointer, and the thread has a non-NULL value associated with the key, the function pointed to is called with the current associated value as its sole argument. The order of destructor calls is unspecified if more than one destructor exists for a thread when it exits.

If, after all the destructors have been called for all non-NULL values with associated destructors, there are still some non-NULL values with associated destructors, then the process is repeated. If, after at least [PTHREAD_DESTRUCTOR_ITERATIONS] iterations of destructor calls for out- standing non-NULL values, there are still some non-NULL values with asso- ciated destructors, the implementation stops calling destructors.

I've wrote a little example with a simple destructor printing "Hello World" for a non NULL thread specific value. As far as I can see, this destructor is called only once (at least on linux fedora and mac os x) even if the thread specific value is still not NULL after the first call to destructor.

Have I missed something?! (PTHREAD_DESTRUCTOR_ITERATIONS = 4 on glibc.)

Here is my little example :

#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;
}
2

2 Answers

4
votes

Seems there isn't a lot of people using pthread in here!

So, again, I'll answer my own question :

The destructor will be called more than one time ONLY if a call to pthread_setspecific is done in the destructor, changing the value of the key.

This is because before calling the destructor, the key pointer is set to null and the pointer is passed to the destructor. So if we want the key pointer not to be null, just have to recall pthread_setspecific in it.

-1
votes

I don't understand the mystery. You only have 1 thread-specific key and only 1 thread that sets the thread-specific data. Therefore the destructor should only execute once as expected.

If you set the thread-specific data somewhere after the pthread_create() in main(), then the destructor will be called twice -- once for the child thread and once for the thread associated with main().