2012年9月5日 星期三

pthread_cond_wait 為什麼會有 mutex

※ 引述《littleboypis (littleboypis)》之銘言:
: 想請教一下各位一個函數
: int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
: 為何 pthread_cond_wait 這個函數的參數需要傳入一個 mutex 呢
: 雖然看了他的解說但還不是很明瞭 為何
: 而且 另一個 int pthread_cond_signal(pthread_cond_t *cond); 也不需要 mutex
: 為何  pthread_cond_wait 要傳入一個 mutex呢
: 謝謝
: 另外在 C 底下要怎麼達到多型 或者 Hooking呢
: 因為我想在程式呼叫 pthread_create 前做一些事情
: 謝謝
以我所知, 分別在於 race condition

用 signal 很容易出現 race condition.
比如
Thread A:
send a job
wait for signal

然後
Thread B:
process incoming job
signaling

看上來很正常, 是吧?
但萬一發生的時序是:

Thread A                Thread B
send job
                      process incoming job
                      signaling

wait for signal


這種情況下, A 就會很傻很天真的一直等下去了

condition 的做法就是加 mutex, 令到 wait for signal 之後才暫時 release mutex, 而這時候 thread B 才能取得 mutex 做 signalling


Thread A                  Thread B
mutex acquire
send job
                          process inocming job
                          企圖 acquire mutex
wait + release mutex
                          mutex acquired
                          signal
wake up+企圖acquire mutex
                           mutex release
mutex acquired


這樣就避免了前面說的 race condition 了
 
 
Example code:
#include 
int thread_flag;
pthread_cond_t thread_flag_cv;
pthread_mutex_t thread_flag_mutex;
void initialize_flag ()
{
 /* Initialize the mutex and condition variable.  */
 pthread_mutex_init (&thread_flag_mutex, NULL);
 pthread_cond_init (&thread_flag_cv, NULL);
 /* Initialize the flag value.  */
 thread_flag = 0;
}
/* Calls do_work repeatedly while the thread flag is set; blocks if
the flag is clear.  */
void* thread_function (void* thread_arg)
{
 /* Loop infinitely.  */
 while (1) {
  /* Lock the mutex before accessing the flag value.  */
  pthread_mutex_lock (&thread_flag_mutex);
   while (!thread_flag) 
/* The flag is clear.  Wait for a signal on the condition
variable, indicating that the flag value has changed.  When the 
signal arrives and this thread unblocks, loop and check the
flag again.  */
    pthread_cond_wait (&thread_flag_cv, &thread_flag_mutex);
/* When we’ve gotten here, we know the flag must be set.  Unlock
the mutex.  */
    pthread_mutex_unlock (&thread_flag_mutex);
/* Do some work.  */
    do_work ();
}
   return NULL;
}
/* Sets the value of the thread flag to FLAG_VALUE.  */
void set_thread_flag (int flag_value)
{
/* Lock the mutex before accessing the flag value.  */
 pthread_mutex_lock (&thread_flag_mutex);
/* Set the flag value, and then signal in case thread_function is
blocked, waiting for the flag to become set.  However,
thread_function can’t actually check the flag until the mutex is
unlocked.  */thread_flag = flag_value;
 pthread_cond_signal (&thread_flag_cv);
/* Unlock the mutex.  */
 pthread_mutex_unlock (&thread_flag_mutex);
}
 

沒有留言: