Thread: Thread-specific data not work fine for me in pthread

  1. #1
    Registered User
    Join Date
    May 2012
    Posts
    33

    Thread-specific data not work fine for me in pthread

    I am programming using pthread. I need a global variable that it has different value for different threads. And threads will use same function to deal with this variable, such as change its value. If one thread change its value, the value in other threads would not be changed. So I tried to use thread specific data, and wrote a example. I need wrap the pthread operations in functions. For exapmle: setspecific(), changedata, printdata(), create_key(), delete_key(), etc.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    pthread_key_t key;
    pthread_key_t key2;
    
    struct test_struct {
        int i;
        float k;
    }struct_data;
    
    int temp;
    
    int setspecificvar () { /* Set specific data for threads */
    
        pthread_setspecific (key, &struct_data);
        pthread_setspecific (key2, &temp);
    
        return 0;
    }
    int changedata (int i, float k, int tempvar) { /* Change specific data for threads */
    
        temp = tempvar;
        struct_data.i = i;
        struct_data.k = k;
    
        return 0;
    }
    
    int printdata (int t) {  /* print specific data for threads */
    
        printf ("The addres in child%d returned from pthread_getspecific(key):0x%p\n",                           \
                t, (struct test_struct *)pthread_getspecific(key));
    
        printf ("The value of members in structure bound to \"key\" in  child%d:\nstruct_data.i:%d\nstruct_data.k: %f\n", \
                t, ((struct test_struct *)pthread_getspecific (key))->i,                            \
                ((struct test_struct *)pthread_getspecific(key))->k);
    
        printf ("------------------------------------------------------\n");
    
        printf ("The addres in child%d returned from pthread_getspecific(key2):0x%p\n",                          \
                t, (int *)pthread_getspecific(key2));
        printf ("The value of \"temp\" bound to \"key2\" in child%d:%d\n", \
                t, *((int *)pthread_getspecific(key2)));
    
        return 0;
    }
    
    void *child1 (void *arg)
    {
        setspecificvar ();
        changedata(10, 3.141500, 110); /* Should not change the data in child2 */
        printdata(1);
    }
    
    void *child2 (void *arg)
    {
        /* sleep (2); */
        setspecificvar ();
    
        changedata(12, 2.141500, 120); /* Should not change the data in child1 */
        printdata(2);
           
        changedata (122, 22.141500, 1220); /* Should not change the data in child1 */
        printdata (2);
    }
    
    int create_key () {
        pthread_key_create (&key, NULL);
        pthread_key_create (&key2, NULL);
        return 0;
    }
    
    int delete_key () {
    
        pthread_key_delete (key);
        pthread_key_delete (key2);
        return 0;
    }
    
    int main (void)
    {
        pthread_t tid1, tid2;
    
        create_key ();
        pthread_create (&tid1, NULL, (void *)child1, NULL);
        pthread_create (&tid2, NULL, (void *)child2, NULL);
        pthread_join (tid1, NULL);
        pthread_join (tid2, NULL);
    
        delete_key ();
    
        return 0;
    }
    I create two threads. When I make one thread sleep 2 seconds. I get correct answer.
    Code:
    The addres in child1 returned from pthread_getspecific(key):0x0x8049c98
    The value of members in structure bound to "key" in  child1:
    struct_data.i:10
    struct_data.k: 3.141500
    ------------------------------------------------------
    The addres in child1 returned from pthread_getspecific(key2):0x0x8049ca0
    The value of "temp" bound to "key2" in child1:110
    The addres in child2 returned from pthread_getspecific(key):0x0x8049c98
    The value of members in structure bound to "key" in  child2:
    struct_data.i:12
    struct_data.k: 2.141500
    ------------------------------------------------------
    The addres in child2 returned from pthread_getspecific(key2):0x0x8049ca0
    The value of "temp" bound to "key2" in child2:120
    The addres in child2 returned from pthread_getspecific(key):0x0x8049c98
    The value of members in structure bound to "key" in  child2:
    struct_data.i:122
    struct_data.k: 22.141500
    ------------------------------------------------------
    The addres in child2 returned from pthread_getspecific(key2):0x0x8049ca0
    The value of "temp" bound to "key2" in child2:1220
    when I comment /* sleep(2); */ , I get uncorrect answer.
    Code:
    The addres in child1 returned from pthread_getspecific(key):0x0x8049c54
    The addres in child2 returned from pthread_getspecific(key):0x0x8049c54
    The value of members in structure bound to "key" in  child2:
    struct_data.i:12
    struct_data.k: 2.141500
    The value of members in structure bound to "key" in  child1:
    struct_data.i:12
    struct_data.k: 2.141500
    ------------------------------------------------------
    The addres in child1 returned from pthread_getspecific(key2):0x0x8049c5c
    The value of "temp" bound to "key2" in child1:120
    ------------------------------------------------------
    The addres in child2 returned from pthread_getspecific(key2):0x0x8049c5c
    The value of "temp" bound to "key2" in child2:120
    The addres in child2 returned from pthread_getspecific(key):0x0x8049c54
    The value of members in structure bound to "key" in  child2:
    struct_data.i:122
    struct_data.k: 22.141500
    ------------------------------------------------------
    The addres in child2 returned from pthread_getspecific(key2):0x0x8049c5c
    The value of "temp" bound to "key2" in child2:1220
    I want get the right result without sleep a thread. One thread should not wait for the other thread to finish to call pthread_setspecific() , right? What should I do? Thanks for your consideration.
    Last edited by ppdouble; 01-01-2013 at 08:36 AM.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    pthread_key_create
    The pthread_key_create() function shall create a thread-specific data key visible to all threads in the process. Key values provided by pthread_key_create() are opaque objects used to locate thread-specific data. Although the same key value may be used by different threads, the values bound to the key by pthread_setspecific() are maintained on a per-thread basis and persist for the life of the calling thread.
    It would seem to be wrong to create the key in one thread (main), and then try and share it in other threads (child1,child2).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    'Allo, 'Allo, Allo
    Join Date
    Apr 2008
    Posts
    639
    What should I do?
    You need a variable that's specific to each thread, say by using malloc or on the stack of the first function the thread runs, and storing that pointer in the TLS. All you're doing now is storing the addresses of the globals (as evidenced by your output, the addresses for each key are the same), then operating on the globals. It "works" with the sleep because it gives the first thread time to interact with them unimpeded, before the second does anything. Without it, they just write to the globals as they like and you end up the unexpected output.

    It would seem to be wrong to create the key in one thread (main), and then try and share it in other threads (child1,child2).
    I'd say that quote says this:
    Allocates a thread local storage key. Any thread of the process can subsequently use this key to store and retrieve values that are local to the thread, because each thread receives its own slot for the key.

  4. #4
    Registered User
    Join Date
    May 2012
    Posts
    33
    Quote Originally Posted by Salem View Post
    pthread_key_create

    It would seem to be wrong to create the key in one thread (main), and then try and share it in other threads (child1,child2).
    If put key pthread_key_create in the thread start_routine. It would be call by every threads. Does that mean create to keys to each threads?

  5. #5
    Registered User
    Join Date
    May 2012
    Posts
    33
    Quote Originally Posted by adeyblue View Post
    You need a variable that's specific to each thread, say by using malloc or on the stack of the first function the thread runs, and storing that pointer in the TLS. All you're doing now is storing the addresses of the globals (as evidenced by your output, the addresses for each key are the same), then operating on the globals. It "works" with the sleep because it gives the first thread time to interact with them unimpeded, before the second does anything. Without it, they just write to the globals as they like and you end up the unexpected output.



    I'd say that quote says this:
    Did I right to define struct_data as global variable? If one thread want use the key, it should create the key and bind the key with a variable, right? And "pthread_key_create" seems like "extern" in C language?

  6. #6
    Registered User
    Join Date
    May 2012
    Posts
    33
    Sorry for late to reply. Does TLS only for windows?

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 03-06-2012, 08:04 AM
  2. Replies: 9
    Last Post: 08-11-2007, 11:41 AM
  3. pthread's - check for running thread
    By xErath in forum Linux Programming
    Replies: 2
    Last Post: 05-29-2005, 03:32 PM
  4. Prog ran fine Friday, now won't work, don't know why
    By Flyer in forum C++ Programming
    Replies: 4
    Last Post: 06-17-2003, 09:38 AM
  5. pthread api vs win32 thread api
    By Unregistered in forum Windows Programming
    Replies: 1
    Last Post: 11-20-2001, 08:55 AM

Tags for this Thread