pthreads queries

Started by
2 comments, last by the_edd 13 years, 11 months ago
Hi, I am playing around with pthreads. I am following Sir.Butenhof's book for the same. I have some confusion about the things mentioned there. Condition variables : So there can be one thread blocking on a condition.. (Thread A) When the condition is signaled by another thread(Thread B)..which by law has to unlock the mutex... is it possible this mutex is intercepted by another thread ?(Thread C , before Thread A locks it ) (perhaps higher priority) I guess this is what he means by Intercepted wakeups ? 1)Since simulating this is hard; will the thread unblock when this intercepted call ends ? 2)Now if multiple threads are awaiting on the same condition variable, which one will be awakened first and given the lock to the mutex ? Spurious wakeups: This means that when you wait on a condition variable, the wait may (occasionally) return when no thread specifically broadcast or signaled that condition variable. 3)Does this mean , pthread_cond_wait returns even though no signal was sent? Or its this a reference to timed wait variant of the same function ? :| 4) Another section mentions; Pthreads does not allow thread 1, for example, to wait on condition variable A specifying mutex A while thread 2 waits on condition variable A specifying mutex B. It is, however, perfectly reason-able for thread 1 to wait on condition variable A specifying mutex A while thread 2 waits on condition variable B specifying mutex A. That is, each condition variable must be associated, at any given time, with only one mutex—but a mutex may have any number of condition variables associated with it. Come to think of it , it would rather make more sense to allow the same... so that two threads can proceed in parallel (assuming exclusivity of data) This : http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SYNCHRONIZATION However says "Any mutex can be used, there is no explicit link between the mutex and the condition variable." 5) Any gains/Advantages of returning from a thread with pthread_exit as opposed to return? I could join and get the return values in either cases. Thanks!
"I think there is a world market for maybe five computers." -- Thomas Watson, Chairman of IBM, 1943
Advertisement
Quote:Original post by Nokturnal
So there can be one thread blocking on a condition.. (Thread A)
When the condition is signaled by another thread(Thread B)..which by law has to unlock the mutex... is it possible this mutex is intercepted by another thread ?(Thread C , before Thread A locks it ) (perhaps higher priority)

You're pretty much at the mercy of the scheduler here. Any signaled threads blocked on the CV are unblocked according to the scheduling policy, and contend for the mutex according to the scheduling policy. In addition, other threads may come along and lock the mutex depending on the scheduling policy.

Quote:1)Since simulating this is hard; will the thread unblock when this intercepted call ends ?

Maybe, maybe not. See above :)

Quote:2)Now if multiple threads are awaiting on the same condition variable, which one will be awakened first and given the lock to the mutex ?

See above, again :) The POSIX documentation is also helpful.

Quote:Spurious wakeups: This means that when you wait on a condition variable,
the wait may (occasionally) return when no thread specifically broadcast or
signaled that condition variable.


3)Does this mean , pthread_cond_wait returns even though no signal was sent? Or its this a reference to timed wait variant of the same function ? :|

It means pretty much what it says, that a wait returns out of the blue. This, in additional to the nature of the scheduler, is another reason why you always should re-check your invariants after a wait in a tight loop:
while(invariant)   pthread_cond_wait(&cv,&mutex);

Quote:4) Another section mentions;

Pthreads does not allow thread 1, for example, to wait on condition variable A specifying mutex A while thread 2 waits on condition variable A specifying mutex B. It is, however, perfectly reason-able for thread 1 to wait on condition variable A specifying mutex A while thread 2 waits on condition variable B specifying mutex A. That is, each condition variable must be associated, at any given time, with only one mutex—but a mutex may
have any number of condition variables associated with it.


Come to think of it , it would rather make more sense to allow the same... so that two threads can proceed in parallel (assuming exclusivity of data)

If you think about it, there really isn't any reason a conditional variable needs more than one mutex at a time. Assuming that a CV could be associated with more than once mutex, and that you could lock/unlock multiple mutexes atomically, they'd always be in the same state anyway, meaning you could always collapse them down to one and it would serve the save purpose.

Quote:This :
http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SYNCHRONIZATION

However says "Any mutex can be used, there is no explicit link between the mutex and the condition variable."

Yes, at any one time a condition variable can be associated with one mutex, however that mutex can change every time you wait. This is what is meant by no explicit link, i.e. no reason why a CV can't use any mutex it wants.
Quote:Original post by Nokturnal

Quote:2)Now if multiple threads are awaiting on the same condition variable, which one will be awakened first and given the lock to the mutex ?

See above, again :) The POSIX documentation is also helpful.


Note to self : Do not read man pages after 1 am. Thanks zipster..!

Moving on : Thread specific data.

If i understand the concept correctly ,it means having a (local) copy of a globally declared data structure..Unless i am missing something... How different is it from directly defining the data in the thread itself? Should't that make it a "thread-specific" data ? Can some one list a practical example where this can come into play

Here is the example :

/* * tsd_once.c * * Demonstrate use of pthread_once to initialize something * exactly once within a multithreaded program. * * Note that it is often easier to use a statically initialized * mutex to accomplish the same result. */#include <pthread.h>#include "errors.h"/* * Structure used as the value for thread-specific data key. */typedef struct tsd_tag {    pthread_t   thread_id;    char        *string;} tsd_t;pthread_key_t tsd_key;           /* Thread-specific data key */pthread_once_t key_once = PTHREAD_ONCE_INIT;/* * One-time initialization routine used with the pthread_once * control block. */void once_routine (void){    int status;    printf ("initializing key\n");    status = pthread_key_create (&tsd_key, NULL);    if (status != 0)        err_abort (status, "Create key");}/* * Thread start routine that uses pthread_once to dynamically * create a thread-specific data key. */void *thread_routine (void *arg){    tsd_t *value;    int status;    status = pthread_once (&key_once, once_routine);    if (status != 0)        err_abort (status, "Once init");    value = (tsd_t*)malloc (sizeof (tsd_t));    if (value == NULL)        errno_abort ("Allocate key value");    status = pthread_setspecific (tsd_key, value);    if (status != 0)        err_abort (status, "Set tsd");    printf ("%s set tsd value %p\n", arg, value);    value->thread_id = pthread_self ();    value->string = (char*)arg;    value = (tsd_t*)pthread_getspecific (tsd_key);    printf ("%s starting...\n", value->string);    sleep (2);    value = (tsd_t*)pthread_getspecific (tsd_key);     printf ("%s done...%p\n", (char*)value->string,value);    return NULL;    }void main (int argc, char *argv[]){    pthread_t thread1, thread2;    int status;    status = pthread_create (&thread1, NULL, thread_routine, "thread 1");    if (status != 0)        err_abort (status, "Create thread 1");    status = pthread_create (&thread2, NULL, thread_routine, "thread 2");    if (status != 0)        err_abort (status, "Create thread 2");    pthread_exit (NULL);}


The output from the above source :


thread 1 set tsd value 0x8c2d4d8
thread 1 starting...
thread 2 set tsd value 0x8c2d4e8
thread 2 starting...
thread 1 done...0x8c2d4d8
thread 2 done...0x8c2d4e8

And the small change i made

void *thread_routine (void *arg){    tsd_t *value;    int status;    status = pthread_once (&key_once, once_routine);    if (status != 0)        err_abort (status, "Once init");    value = (tsd_t*)malloc (sizeof (tsd_t));    printf ("%s set tsd value %p\n", (char*)arg, value);    value->thread_id = pthread_self ();    value->string = (char*)arg;    printf ("%s starting...\n",(char*) value->string);    sleep (2);    //printf ("%s done...\n", (char*)value->string);    printf ("%s done...%p\n", (char*)value->string,value);    return NULL;}


O/P:

thread 1 set tsd value 0x8c2d4d8
thread 1 starting...
thread 2 set tsd value 0x8c2d4e8
thread 2 starting...
thread 1 done...0x8c2d4d8
thread 2 done...0x8c2d4e8


Thanks!

[Edited by - Nokturnal on May 23, 2010 10:08:11 AM]
"I think there is a world market for maybe five computers." -- Thomas Watson, Chairman of IBM, 1943
Quote:Original post by Nokturnal
Moving on : Thread specific data.

If i understand the concept correctly ,it means having a (local) copy of a globally declared data structure.


Local to the thread, yes. It's certainly used a lot more for global objects that anything else in my experience.

Quote:How different is it from directly defining the data in the thread itself? Should't that make it a "thread-specific" data ?

In general, this is indeed what you should do.

Quote:Can some one list a practical example where this can come into play

The examples that come to mind are the handful of functions in the C standard library that were defined without threads in mind.

For example, localtime() returns a pointer to a statically allocated object. This doesn't play well with multiple threads. Some standard library implementations (Microsoft's for instance) use a static thread-specific object to store the tm struct, side-stepping this issue in threaded code.

If these function were to be designed from scratch they would surely not contain this flaw. You'd have to pass in the structure to be filled, or something.

In summary, the fact that you're questioning the utility of thread local storage is a good probably thing :) You shouldn't need it very often.

This topic is closed to new replies.

Advertisement