views:

450

answers:

2

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;
}
A: 

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 into the constructor, 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.

claferri
A: 

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().

Apprentice Queue
The destructor may be called several times for the SAME thread-specific data! The fact that I only have one thread doesn't change this statement.
claferri
The point is there is only 1 set() therefore at most 1 destructor call. If you had 2 sets(), there would be at most 2 destructor calls. Your original question asked "why only executed once?" and I told you why. Also it has nothing to do with the constructor. If you call set() 10 times within your program, it will call the destructor at most 10 times. The example in http://www.opengroup.org/onlinepubs/000095399/functions/pthread_key_create.html clarifies this.
Apprentice Queue