Thread synchronization: Condvar

A condvar (condition variable) is used together with a mutex lock. It blocks a thread within a critical section until some condition is satisfied.
Initialization and destroy
  •  pthread_condattr_init(pthread_condattr_t *attr;);
  • pthread_cond_init(pthread_cond_t *condv, pthread_condattr_t *attr);
  • pthread_cond_destroy(pthread_cond_t *condv);
Condvar attributes
  • A condvar can be PTHREAD_PROCESS_PRIVATE(default) or PTHREAD_PROCESS_SHARED.
    • pthread_condattr_setshared(&attr, int shared);
    • pthread_condattr_getshared(&attr, &shared);
  •  A condvar can use different clocks: CLOCK_REALTIME, CLOCK_SOFTTIME, CLOCK_MONOTONIC (not affected by changes to the system time). It will be used to for pthread_cond_timewait(). The default value refers to the system clock??
  • pthread_condattr_setclock(&attr,clock_id)
  • pthread_condattr_getclock(&attr, *clock_id);
Wait
  • pthread_cond_wait(&condv, &mutex);
    • this function blocks the calling thread on the conditional variable (condv), and unlocks the associated mutex (mutex).
    • the thread is blocked until
      • another thread calls pthread_cond_signal() or pthread_cond_boradcast(), or
      • a signal is delivered to the thread, or
      • the thread is canceled.
        • In all cases, the thread reacquires the mutex before being unblocked. It means, even another thread calls _signal(), or _broadcast(), this thread might still be blocked, until the other thread calls pthread_mutex_unlock() to release the mutex.
  • pthread_cond_timedwait(&condv, &mutex, const struct timespec *abstime);
    •  returns
      • EOK, if success, or was interrupted by a signal.
      • ETIMEOUT if timeout.
      • EPERM: the thread doesn’t own the mutex.
      • If the thread is cancelled, the cleanup handler is executed, after the thread reacquires the mutex.
Unblock
  • pthread_cond_signal(&cond): unblock the highest priority thread.
  • pthread_cond_broadcast(&cond): unblock all the threads.
Useful tips
  • A thread must lock mutex first,  then wait for condv (On return from the function, the mutex is again locked and owned by the called thread).
  • Don’t use a recursive mutex with condition variables.
  • Make sure that the thread’s cleanup handlers unlock the mutex.
  • use while loop while waiting for a condvar. reasons:
    • POSIX cannot guarantee no false wakeups (e.g. Multiprocessor systems);
    • we need test to ensure the condition matches our criteria.
  • pthread_cond_timedwait() uses struct timespec to specify an absolute timeout value.
    • Use clock_gettime(clock_id, &ts) to get the system time
      • Don’t use the kernel call ClockTime_r(clock_id, const &new, &old)
  • More on get time funtions
    • ClockTime_rreturns the time in nano seconds, while clock_gettime() returns struct timespec.
    • two useful functions:
      • void nsec2timespec(&tp, nsec);
      • uint64_t timespec2nsec(&tp);
 Example(30ms timeout)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_nsec += 30 * 1000000ULL;
pthread_mutex_lock(&mutex);
// form 1
while (pthread_cond_timedwait(&condv, &mutex, &ts) == EOK) {
// get the condv, or interrupted by a signal
   If(condition is true) {
        Break;
   }
}
// an error returned by pthread_cond_timedwait(), possibly ETIMEOUT.
// form 2
While(contition is false) {
   If(pthread_cond_timedwait(&condv, &mutex, &ts) != EOK) {
    Break;
   }
}
pthread_mutex_unlock(&mutex);
….
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s