Monday, January 12, 2009

Linux - Threads - Mutex

Mutexes:

Mutexes have two basic operations, lock and unlock. If a mutex is unlocked and a thread calls lock, the mutex locks and the thread continues. If however the mutex is locked, the thread blocks until the thread 'holding' the lock calls unlock.

There are 5 basic functions dealing with mutexes.

int
pthread_mutex_init (pthread_mutex_t *mut, const pthread_mutexattr_t *attr);
Note that you pass a pointer to the mutex, and that to use the default attributes just pass NULL for the second parameter.
int
pthread_mutex_lock (pthread_mutex_t *mut);
Locks the mutex :).
int
pthread_mutex_unlock (pthread_mutex_t *mut);
Unlocks the mutex :).
int
pthread_mutex_trylock (pthread_mutex_t *mut);
Either acquires the lock if it is available, or returns EBUSY.
int
pthread_mutex_destroy (pthread_mutex_t *mut);
Deallocates any memory or other resources associated with the mutex.


THREAD 1                       THREAD 2
pthread_mutex_lock (&mut);     
                               pthread_mutex_lock (&mut); 
a = data;                      /* blocked */
a++;                           /* blocked */
data = a;                      /* blocked */
pthread_mutex_unlock (&mut);   /* blocked */
                               b = data;
                               b--;
                               data = b;
                               pthread_mutex_unlock (&mut);
[data is fine.  The data race is gone.]

Condition Variables:

To sleep a thread until some condition is satisfied, which other thread will make.

 pthread_mutex_lock(&mutex);         /* lock mutex           */
        while (!predicate) {                    /* check predicate      */
          pthread_cond_wait(&condvar,&mutex);   /* go to sleep - recheck
                                                   pred on awakening    */
        }
        pthread_mutex_unlock(&mutex);               /* unlock mutex         */

when pthread_cond_wait() is called, the mutex is unlocked and the thread goes to sleep waiting for the condition. We need to wake up this thread  from another thread

       pthread_mutex_lock(&mutex);         /* lock the mutex       */         predicate=1;                            /* set the predicate    */         pthread_cond_broadcast(&condvar);   /* wake everyone up     */         pthread_mutex_unlock(&mutex);               /* unlock the mutex     */

pthread_cond_broadcast() will wake up all the threads waiting for that condition.
When waken up, pthread_cond_wait() will relock the mutex and do further processing.

List of major pthreads routines

  • pthread_cancel    - cancel running thread
  • pthread_create - Creates a thread
  • pthread_cond_broadcast  - broadcast that the condition variable is changed to all thereads that are waiting
  • pthread_cond_destroy - Destroy a condition variable object. The condition variable should be unused, with no threads waiting for it. The memory for the object is left intact; it is up to the caller to deallocate it.
  • pthread_cond_init  - Initialize a condition variable object, using the provided condition attributes object
  • pthread_cond_signal  - Wakeup the highest priority thread waiting on a condition variable.Wakes up only one thread 
  • pthread_cond_wait  - The current thread is made to wait until the condition variable is signaled or broadcast. The mutex is released prior to waiting, and reacquired before returning.
  • pthread_detach - The thread is detached from its parent ( the one which created it.. Here no need to join later ). If the thread has already exited, its resources are released.
  • pthread_exit  - The current thread is terminated, with its status value made available to the parent using pthread_join.
  • pthread_join  - The current thread indicates that it would like to join with the target thread specified by tid. If the target thread has already terminated, its exit status is provided immediately to the caller. If the target thread has not yet exited, the caller is made to wait. Once the target has exited, all of the threads waiting to join with it are woken up, and the target’s exit status provided to each.
  • pthread_mutex_destroy - The mutex object is destroyed, although the memory for the object is not deallocated. The mutex must not be held.
  • pthread_mutex_init -  Initialize the mutex
  • pthread_mutex_lock - lock the mutex
  • pthread_mutex_unlock - unlock the mutex
  • pthread_mutex_trylock  - If we call pthread_mutex_trylock on an unlocked mutex, you will lock the mutex as if you had called pthread_mutex_lock, and pthread_mutex_trylock will return zero. However, if the mutex is already locked by another thread, pthread_mutex_trylock will not block. Instead, it will return immediately with the error code EBUSY.The mutex lock held by the other thread is not affected.You may try again later to lock the mutex.

  • We have 3 kinds of mutexes
    fast mutex (by default all mutex are of this type)
    recursive mutex
    error checking flag mutex

    if we call pthread_mutex_lock on a fast mutex two times in the same thread without unlocking, this will cause deadlock. 

    A recursive mutex maysafely be locked many times by the same thread.The mutex remembers howmany times pthread_mutex_lock was called on it by the thread that holds the lock; that thread must make the same number of calls to pthread_mutex_unlock before the mutex is actually unlocked and another thread is allowed to lock it.

    By default, Linux mutexes are fast mutexes. We can modify it by using mutex attributes as shown below

    pthread_mutexattr_t attr;
    pthread_mutex_t mutex;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_setkind_np (&attr, PTHREAD_MUTEX_RECURSIVE_NP
    );  // we can use PTHREAD_MUTEX_ERRORCHECK_NP for error cheking flags
    pthread_mutex_init (&mutex, &attr);
    pthread_mutexattr_destroy (&attr);


No comments: