Thread: pthread_cond_wait "tricky" and may be a little dangerous (for newbies like me) behavi

  1. #1
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251

    pthread_cond_wait "tricky" and may be a little dangerous (for newbies like me) behavi

    From the down attached source code (Linux kernel 2.6.18.6)

    Code:
    static inline void suspend_with_cancellation(pthread_descr self)
    {
      sigset_t mask;
      sigjmp_buf jmpbuf;
    
      sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */
      sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */
      /* No need to save the signal mask, we'll restore it ourselves */
      if (sigsetjmp(jmpbuf, 0) == 0) {
        self->p_cancel_jmp = &jmpbuf;
        if (! (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE)) {
          do {
    	self->p_signal = 0;
            sigsuspend(&mask);               /* Wait for a signal */
          } while (self->p_signal != __pthread_sig_restart);//sig_restart is sent by pthread_cond_broadcast() or pthread_cond_signal()  //it is not clear if a cancel unblocks or not //it seems no?!
        }
        self->p_cancel_jmp = NULL;
      } else {
        sigaddset(&mask, __pthread_sig_restart); /* Reblock the restart signal */
        sigprocmask(SIG_SETMASK, &mask, NULL);
      }
    }
    
    
    int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
    {
      volatile pthread_descr self = thread_self();
    
      __pthread_lock(&cond->__c_lock, self);
      enqueue(&cond->__c_waiting, self);
      __pthread_unlock(&cond->__c_lock);
      pthread_mutex_unlock(mutex);
      suspend_with_cancellation(self);
      /* This is a cancellation point */
      if (THREAD_GETMEM(self, p_canceled)
          && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
        /* Remove ourselves from the waiting queue if we're still on it */
        __pthread_lock(&cond->__c_lock, self);
        remove_from_queue(&cond->__c_waiting, self);
        __pthread_unlock(&cond->__c_lock);
        pthread_exit(PTHREAD_CANCELED);
      }
      return 0;
    }
    it seems that pthread_cond_wait() has a little bit strange behaviour:
    (1) if a pthread_cancel is received before executing pthread_cond_wait -> the mutex is locked and immediately cancelation is executed (without waiting for a pthread_cond_broadcast/signal() )
    (2) if a pthread_cancel is received during execution of pthread_cond_wait it depends:
    (2.1) if cancel is recieved inside suspend_with_cancellation before do{}while
    same as (1)
    (2.2) if cancel is received during do{}while , the thread keeps blocked-waiting for a pthread_cond_broadcast/signal(). Only after another thread has sent pthread_cond_broadcast/signal() this thread will go on and execute cancelation!

    Is it right?

    This means that in the following 3 examples only the first is safe: (please tell me if you agree)

    Code:
    (1)
    Thread 1
     pthread_mutex_lock(mutex);
      pthread_cleanup_push(pthread_mutex_unlock,mutex);
      while (...) pthread_cond_wait(cond,mutex); 
    ......
      pthread_cleanup_pop(0);
      pthread_mutex_unlock(mutex);
    
    Thread 2
    pthread_mutex_lock(mutex);
    ....
    pthread_cond_broadcast(cond);
    pthread_mutex_unlock(mutex);
    
    
    (2)
    Thread 1
     pthread_mutex_lock(mutex);
      pthread_cleanup_push(pthread_mutex_unlock,mutex);
      while (boolean condition) pthread_cond_wait(cond,mutex); 
    ......
      pthread_cleanup_pop(0);
      pthread_mutex_unlock(mutex);
    
    Thread 2
    pthread_mutex_lock(mutex);
    ....
    if ( !boolean condition) pthread_cond_broadcast(cond);
    pthread_mutex_unlock(mutex);
    
    
    (3)
    (1)
    Thread 1
     pthread_mutex_lock(mutex);
      pthread_cleanup_push(pthread_mutex_unlock,mutex);
      while (...) pthread_cond_wait(cond,mutex); 
    ......
      pthread_cleanup_pop(0);
      pthread_mutex_unlock(mutex);
    
    Thread 2
    pthread_mutex_lock(mutex);
    ....
    some function which is a cancelation point
    ....
    pthread_cond_broadcast(cond);
    pthread_mutex_unlock(mutex);

  2. #2
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    >> From the down attached source code (Linux kernel 2.6.18.6)
    Well, pthreads is part of glibc, not the kernel. Where did you get that code? It looks like really old LinuxThreads code. NPTL is the preferred pthread implementation for Linux these days.

    http://en.wikipedia.org/wiki/LinuxThreads

    Source for both is here: http://sourceware.org/cgi-bin/cvsweb.cgi/?cvsroot=glibc
    LinuxThreads is in \linuxthreads\
    NPTS is in \libc\nptl\

    More info on the two: http://www-128.ibm.com/developerwork...ThreadsAndNPTL

    I would concentrate on what the standard says about how these functions should behave - instead of looking at some implementation.

    POSIX standard can be read online here (may need to register): http://www.opengroup.org/onlinepubs/009695399/

    gg

  3. #3
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Thank you very much
    Yes sorry it's true. It was not form kernel, it was taken from the source of
    glibc-linuxthreads-2.1.2
    taken form the site http://www.eu.kernel.org/pub/linux/libs/glibc/
    Is it linuxthreads or NPTL ?

    I had a look at the code cause the man specifics were not enough explicit and clear
    I have to look at the implementation cause threads under linux are not 100%-POSIX compliant and my system needs industrial reliability!
    Last edited by mynickmynick; 05-09-2008 at 04:33 AM.

  4. #4
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Well actually a more robust and general structure is the following:
    Code:
    Thread 1
     pthread_mutex_lock(mutex);
      pthread_cleanup_push(pthread_mutex_unlock,mutex);
      while (.. Bool Condition ..) pthread_cond_wait(cond,mutex); 
    ......
      pthread_cleanup_pop(0);
      pthread_cond_broadcast(cond);//only this line was added for a general n threads situation
      pthread_mutex_unlock(mutex);
    
    Thread 2
    pthread_mutex_lock(mutex);
    ....
    pthread_cond_broadcast(cond);
    pthread_mutex_unlock(mutex);
    guess this should work fine and general for LinuxThreads and for NPTL as well
    Actually the source code for NPTL-pthread_cond_wait() is quite difficult to read (to me). But it seems that in NPTL the mutex is left unlocked in case of cancelation of a waiting-cond thread. So Thread 2 could probably perform also a
    Code:
     if(boolCond) pthread_cond_broadcast but()
    in any case that would make the example less general and robust and the code less separable (it makes bilateral assumptions: One has to be careful to keep same BoolCond on both sides).
    The same holds for Thread1.
    Last edited by mynickmynick; 05-14-2008 at 11:12 AM.

  5. #5
    Alessio Stella
    Join Date
    May 2008
    Location
    Italy, Bologna
    Posts
    251
    Thanks a lot but
    Could you please suggest a site where one can download all files together (not only one at a time??)
    Thanks

    Quote Originally Posted by Codeplug View Post
    >> From the down attached source code (Linux kernel 2.6.18.6)

    Source for both is here: http://sourceware.org/cgi-bin/cvsweb.cgi/?cvsroot=glibc
    LinuxThreads is in \linuxthreads\
    NPTS is in \libc\nptl\


    gg

Popular pages Recent additions subscribe to a feed