Linux 多線程服務端編程筆記(第二章)

Q1:

在編寫一個自己的MutexLock,MutexLockGuard,Condition_var時,為何pthread的condition的wait及signal操作需要傳入mutex?

A1:

具體的可見這個帖子:c - Does pthread_cond_wait(&cond_t, &mutex); unlock and then lock the mutex? - Stack Overflow

必須知道條件變量并不需要互斥鎖來保護,網絡上說需要保護條件變量的都是胡扯.回答中這樣說道:

The condition variable doesn't need mutual exclusion protection; the predicate data does.

那為什么在wait和signal的時候總是在外層包一層mutex呢?
那是因為我們必須要保護謂詞(predicate),我們使用條件變量的時候是要和謂詞一起用的,要是我們想實現這樣一個功能:一旦資源數大于0就進行處理,我們可以有下面的代碼(這其實也是信號量的實現原理)

extern int rc_count; // 表示資源值
pthread_mutex_t mutex;//是為了保護rc_count,即rc_count就是謂詞
pthread_cond_t cond;

pthread_mutex_lock(&mutex);
while(rc_count <= 0)
{
  pthread_cond_wait(&cond,&mutex);//只有當資源量大于0時才可能跳出循環(huán).
}
pthread_mutex_unlock(&mutex);

簡單來說就是condition的wait和signal是一種簡單的信號機制,在wait時,就將當前線程阻塞,并且還要把負責將mutex打開,否則遵循mutex機制的其他乖孩子線程無法更改謂詞,和發(fā)出signal了.這樣wait的線程就會一直阻塞,無法進行下一步操作.而在wait退出的時候,會負責將mutex鎖上,從而wait的線程從wait剛退出就自動擁有這個mutex所保護的謂詞.帖子中說道:

Never change, nor check, the predicate condition unless the mutex is locked. Ever.

注意,我這里所說的一直阻塞其實只會發(fā)生在謂詞改變不了的時候.我們一般在signal的線程中采用下面的兩種規(guī)范寫法:

pattern1

pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cv);

pattern2

pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);

想想如果我們的線程都是乖孩子,意味著只有獲取鎖才能改變謂詞,這樣的話如果因為某些粗心的程序員寫出了下面的代碼:

some code
pthread_cond_signal(&cv)//錯誤添加了這一行
some code
pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);

由于我們wait端一般是這樣寫的:

while(rc_count <= 0)
{
  pthread_cond_wait(&cond,&mutex);
}

這樣的話,即使錯誤信號發(fā)出,只要謂詞不滿足條件一樣是線程阻塞.

下面是一個例子:

int WaitForPredicate()
{
    // lock mutex (means:lock access to the predicate)
    pthread_mutex_lock(&mtx);

    // we can safely check this, since no one else should be 
    // changing it unless they have the mutex, which they don't
    // because we just locked it.
    while (!predicate)
    {
        // predicate not met, so begin waiting for notification
        // it has been changed *and* release access to change it
        // to anyone wanting to by unlatching the mutex, doing
        // both (start waiting and unlatching) atomically
        pthread_cond_wait(&cv,&mtx);

        // upon arriving here, the above returns with the mutex
        // latched (we own it). The predicate *may* be true, and
        // we'll be looping around to see if it is, but we can
        // safely do so because we own the mutex coming out of
        // the cv-wait call. 
    }

    // we still own the mutex here. further, we have assessed the 
    //  predicate is true (thus how we broke the loop).

    // take whatever action needed. 

    // You *must* release the mutex before we leave. Remember, we
    //  still own it even after the code above.
    pthread_mutex_unlock(&mtx);
}
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容