Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a global variable that is thread-specific in C using POSIX threads?

I am learning about POSIX threads and I have come to the section on Thread Specific Data. The book does an excellent example using a file descriptor. However, I wanted to do the same example on my own, except this time using a global variable. However, I am having some difficulty fully grasping this concept.

What I want to do is the following:

  • Create a global integer
  • Declare a key for the global int

in main:

  • set global integer to be a value eg. 10
  • create a key for it without any clean up
  • create 4 threads and send them to execute thread_func
  • check if value is still 10, since threads only see a copy of it

in thread_func:

  • use pthread_setspecific(key,global variable) to create a local instance - not sure if I am interpreting this correctly
  • call a function - dosomething()
  • exit

in do_something

  • create a local pointer and assign it to pthread_getspecific(key) - this should get me a thread specific version of the global variable
  • change the value of what is stored at the local pointer to 2
  • exit

Here's the code:

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

#define NUMTHREADS 4

pthread_key_t glob_var_key;
int glob_var;

void do_something()
{
    //get thread specific data
    int* glob_spec_var = (int*) pthread_getspecific(glob_var_key);
    printf("Thread %d glob_spec before mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
    *glob_spec_var = 2;
    printf("Thread %d glob_spec after mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
}

void* thread_func(void *arg)
{
    pthread_setspecific(glob_var_key, &glob_var);
    do_something();
    pthread_exit(NULL);
}

int main(void)
{
    pthread_t threads[NUMTHREADS];
    int i;
    glob_var = 10;
    pthread_key_create(&glob_var_key,NULL);
    printf("Main: glob_var is %d\n", glob_var);
    for (i=0; i < NUMTHREADS; i++)
    {
        pthread_create(&threads[i],NULL,thread_func,NULL);
    }

    for (i=0; i < NUMTHREADS; i++)
    {
        pthread_join(threads[i], NULL);
    }
    printf("Main: glob_var is %d\n", glob_var);

    return 0;
}

From what I understood, when you call pthread_getspecific, each thread is supposed to have its own unique memory address for the memory addresses - which I did not find to be the case here. I know I am not going about this correctly and when I did try to look at the memory addresses for each thread when doing getspecific, I saw the same memory address. Perhaps someone can point me to an example where they use a global variable (not file descriptors) and they have thread-specific usage in which threads look at it as a local variable.

like image 526
Cal Avatar asked Feb 26 '13 22:02

Cal


People also ask

What is Posix thread in C?

The POSIX thread libraries are a standards based thread API for C/C++. It allows one to spawn a new concurrent process flow. It is most effective on multi-processor or multi-core systems where the process flow can be scheduled to run on another processor thus gaining speed through parallel or distributed processing.

Can threads access global variables in C?

But to answer your question, any thread can access any global variable currently in scope.

What function creates a Posix thread?

POSIX provides pthread_create() API to create a thread i.e. int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); #include <pthread.


3 Answers

This is not an answer, but a side note:

If you are working on Linux-specific code, you can use the __thread keyword. Essentially,

static __thread int counter = 5;

creates a different counter variable for each thread, initialized to value 5 whenever a new thread gets created. Such code is future-compatible with C11, since C11 standardized the same semantics using the _Thread_local keyword. This is much saner than the POSIX thread-specific functions (which have implementation-specific limits, and are quite cumbersome compared to the __thread keyword), on all architectures using C, except those that have declared C99 and later "standard non grata" (i.e., Microsoft).

See the Thread-Local Storage chapter in GCC documentation for details.

like image 193
Nominal Animal Avatar answered Oct 16 '22 04:10

Nominal Animal


The purpose of TLS (thread-local storage) is to provide an defined mechanism whereby code can retrieve thread-specific data stored in a database accessed by a all-threads-known shared key. Your code is storing the same data in TLS: the address of a single global variable). Therefore when a thread requests this data using the tls-key, they will all get back the same address.

I think you intend your code to do something like this:

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

#define NUMTHREADS 4

pthread_key_t glob_var_key;

void do_something()
{
    //get thread specific data
    int* glob_spec_var = pthread_getspecific(glob_var_key);
    printf("Thread %d before mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
    *glob_spec_var += 1;
    printf("Thread %d after mod value is %d\n", (unsigned int) pthread_self(), *glob_spec_var);
}

void* thread_func(void *arg)
{
    int *p = malloc(sizeof(int));
    *p = 1;
    pthread_setspecific(glob_var_key, p);
    do_something();
    do_something();
    pthread_setspecific(glob_var_key, NULL);
    free(p);
    pthread_exit(NULL);
}

int main(void)
{
    pthread_t threads[NUMTHREADS];
    int i;

    pthread_key_create(&glob_var_key,NULL);
    for (i=0; i < NUMTHREADS; i++)
        pthread_create(threads+i,NULL,thread_func,NULL);

    for (i=0; i < NUMTHREADS; i++)
        pthread_join(threads[i], NULL);

    return 0;
}

Output

Thread 2625536 before mod value is 1
Thread 741376 before mod value is 1
Thread 3162112 before mod value is 1
Thread 3698688 before mod value is 1
Thread 2625536 after mod value is 2
Thread 741376 after mod value is 2
Thread 3162112 after mod value is 2
Thread 3698688 after mod value is 2
Thread 2625536 before mod value is 2
Thread 741376 before mod value is 2
Thread 3162112 before mod value is 2
Thread 3698688 before mod value is 2
Thread 2625536 after mod value is 3
Thread 741376 after mod value is 3
Thread 3162112 after mod value is 3
Thread 3698688 after mod value is 3
like image 23
WhozCraig Avatar answered Oct 16 '22 04:10

WhozCraig


In general, what you're looking for is "thread local storage". Here are a few links:

  • http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Frzahw%2Frzahwex1.htm

  • http://en.wikipedia.org/wiki/Thread-local_storage

Choosing pthread_getspecific() is correct. Here's a good example:

  • http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fapis%2Fusers_34.htm

Please review the above example: I think it will point you to the problem ... or suggest a good alternative.

IMHO...

like image 27
paulsm4 Avatar answered Oct 16 '22 02:10

paulsm4