詳解linux互斥鎖 pthread_mutex和條件變量pthread_cond


[cpp] view plaincopy =============================================================   
   
int pthread_create(   
               pthread_t *tid,   
               const pthread_attr_t *attr,   
               void*(*start_routine)(void*),   
               void *arg   
               );   
//參數tid 用於返回新創建線程的線程號;   
//start_routine 是線程函數指針,線程從這個函數開始獨立地運行;   
//arg 是傳遞給線程函數的參數。由於start_routine 是一個指向參數類型為void*,返回值為void*的指針,所以如果需要傳遞或返回多個參數時,可以使用強制類型轉化。   
   
=============================================================   
   
void pthread_exit(   
             void* value_ptr   
             );   
// 參數value_ptr 是一個指向返回狀態值的指針。   
   
=============================================================   
   
int pthread_join(   
             pthread_t tid ,   
             void **status   
             );   
// 參數tid 是希望等待的線程的線程號,status 是指向線程返回值的指針,線程的返回值就是pthread_exit 中的value_ptr 參數,或者是return語句中的返回值。該函數可用於線程間的同步。   
=============================================================   
   
int pthread_mutex_init(   
                   pthread_mutex_t *mutex,   
                   const pthread_mutex_attr_t* attr   
                   );   
//該函數初始化一個互斥體變量,如果參數attr 為NULL,則互斥   
//體變量mutex 使用默認的屬性。   
   
=============================================================   
   
int pthread_mutex_lock(   
                   pthread_mutex_t *mutex   
                   );   
// 該函數用來鎖住互斥體變量。如果參數mutex 所指的互斥體已經   
//被鎖住了,那么發出調用的線程將被阻塞直到其他線程對mutex 解鎖。   
   
=============================================================   
   
int pthread_mutex_trylock(   
                      pthread_t *mutex   
                      );   
//該函數用來鎖住mutex 所指定的互斥體,但不阻塞。如果該互斥   
//體已經被上鎖,該調用不會阻塞等待,而會返回一個錯誤代碼。   
   
=============================================================   
   
int pthread_mutex_unlock(   
                     pthread_mutex_t *mutex   
                     );   
//該函數用來對一個互斥體解鎖。如果當前線程擁有參數mutex 所   
//指定的互斥體,該調用將該互斥體解鎖。   
   
=============================================================   
   
int pthread_mutex_destroy (   
                       pthread_mutex_t *mutex   
                       );   
//該函數用來釋放分配給參數mutex 的資源。調用成功時返回值為   
//0, 否則返回一個非0 的錯誤代碼。   
   
=============================================================   
   
int pthread_cond_init(   
                  pthread_cond_t *cond,   
                  const pthread_cond_attr_t*attr   
                  );   
//該函數按參數attr指定的屬性創建一個條件變量。調用成功返回,   
//並將條件變量ID 賦值給參數cond,否則返回錯誤代碼。   
   
=============================================================   
   
int pthread_cond_wait (   
                   pthread_cond_t *cond ,   
                   pthread_mutex_t*mutex   
                   );   
// 該函數調用為參數mutex 指定的互斥體解鎖,等待一個事件(由   
//參數cond 指定的條件變量)發生。調用該函數的線程被阻塞直到有其他   
//線程調用pthread_cond_signal 或pthread_cond_broadcast 函數置相應的條   
//件變量,而且獲得mutex 互斥體時才解除阻塞。   
   
=============================================================   
   
int pthread_cond_timewait(   
                      pthread_cond_t *cond ,   
                      pthread_mutex_t*mutex ,   
                      const struct timespec *abstime   
                      );   
// 該函數與pthread_cond_wait 不同的是當系統時間到達abstime 參數指定的時間時,被阻塞線程也可以被喚起繼續執行。   
   
=============================================================   
   
int pthread_cond_broadcast(   
                       pthread_cond_t *cond   
                       );   
// 該函數用來對所有等待參數cond所指定的條件變量的線程解除阻塞,調用成功返回0,否則返回錯誤代碼。   
   
=============================================================   
   
int pthread_cond_signal(   
                    pthread_cond_t *cond   
                    );   
// 該函數的作用是解除一個等待參數cond所指定的條件變量的線程的阻塞狀態。當有多個線程掛起等待該條件變量,也只喚醒一個線程。   
   
=============================================================   
   
int pthread_cond_destroy(   
                     pthread_cond_t *cond   
                     );   
// 該函數的作用是釋放一個條件變量。釋放為條件變量cond 所分配的資源。調用成功返回值為0,否則返回錯誤代碼。   
   
=============================================================   
   
int pthread_key_create(   
                   pthread_key_t key ,   
                   void(*destructor(void*))   
                   );   
// 該函數創建一個鍵值,該鍵值映射到一個專有數據結構體上。如果第二個參數不是NULL,這個鍵值被刪除時將調用這個函數指針來釋放數據空間。   
   
=============================================================   
   
int pthread_key_delete(   
                   pthread_key_t *key   
                   );   
// 該函數用於刪除一個由pthread_key_create 函數調用創建的TSD鍵。調用成功返回值為0,否則返回錯誤代碼。   
   
=============================================================   
   
int pthread_setspecific(   
                    pthread_key_t key ,   
                    const void(value)   
                    );   
// 該函數設置一個線程專有數據的值,賦給由pthread_key_create 創建的TSD 鍵,調用成功返回值為0,否則返回錯誤代碼。   
   
=============================================================   
   
void *pthread_getspecific(   
                    pthread_key_t *key   
                    );   
// 該函數獲得綁定到指定TSD 鍵上的值。調用成功,返回給定參數key 所對應的數據。如果沒有數據連接到該TSD 鍵,則返回NULL。   
   
=============================================================   
   
int pthread_once(   
             pthread_once_t* once_control,   
             void(*init_routine)(void)   
             );   
//該函數的作用是確保init_routine 指向的函數,在調用pthread_once的線程中只被運行一次。once_control 指向一個靜態或全局的變量。   
   
=============================================================   
   
     在code review中,我會發現很多人喜歡在pthread_mutex_lock()和pthread_mutex_unlock(()之間調用 pthread_cond_signal或者pthread_cond_broadcast函數,從邏輯上來說,這種使用方法是完全正確的。但是在多線程 環境中,這種使用方法可能是低效的。posix1標准說,pthread_cond_signal與pthread_cond_broadcast無需考 慮調用線程是否是mutex的擁有者,也就是所,可以在lock與unlock以外的區域調用。如果我們對調用行為不關心,那么請在lock區域之外調用 吧。這里舉個例子:   
   
       我們假設系統中有線程1和線程2,他們都想獲取mutex后處理共享數據,再釋放mutex。請看這種序列:   
   
1)線程1獲取mutex,在進行數據處理的時候,線程2也想獲取mutex,但是此時被線程1所占用,線程2進入休眠,等待mutex被釋放。   
   
2)線程1做完數據處理后,調用pthread_cond_signal()喚醒等待隊列中某個線程,在本例中也就是線程2。線程1在調用 pthread_mutex_unlock()前,因為系統調度的原因,線程2獲取使用CPU的權利,那么它就想要開始處理數據,但是在開始處理之 前,mutex必須被獲取,很遺憾,線程1正在使用mutex,所以線程2被迫再次進入休眠。   
   
3)然后就是線程1執行pthread_mutex_unlock()后,線程2方能被再次喚醒。   
   
從這里看,使用的效率是比較低的,如果再多線程環境中,這種情況頻繁發生的話,是一件比較痛苦的事情。   
所以覺得,如果程序不關心線程可預知的調度 行為,那么最好在鎖定區域以外調用他們吧:-)   
如果讀者喜歡英文的話,可以參考:   
http://www.opengroup.org/onlinepubs/007908799/xsh/pthread_cond_broadcast.html   
這 里羅嗦幾句,對於   
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);   
int pthread_cond_timedwait(pthread_cond_t *cond,    
    pthread_mutex_t *mutex, const struct timespec *abstime);   
,一定要在mutex的鎖定區域內使用。   
如果要正確的使用pthread_mutex_lock與pthread_mutex_unlock,請參考   
pthread_cleanup_push 和pthread_cleanup_pop宏,它能夠在線程被cancel的時候正確的釋放mutex!   
http://blog.csdn.net/hello_wyq/archive/2006/08/23/1108264.aspx   
   
PTHREAD_COND(3)   
名稱   
pthread_cond_init, pthread_cond_destroy, pthread_cond_signal,   
pthread_cond_broadcast, pthread_cond_wait, pthread_cond_timedwait - 狀態操作。   
大綱   
#include    
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);   
int pthread_cond_signal(pthread_cond_t *cond);   
int pthread_cond_broadcast(pthread_cond_t *cond);   
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);   
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct    
timespec *abstime);   
int pthread_cond_destroy(pthread_cond_t *cond);   
描述   
狀態變量是一種同步設備,它允許線程掛起並放棄CPU時間以等待某些共享變量滿足狀態。操作狀態變量的基本操作:當狀態滿足時發送信號,等待狀態滿足,在其它線程發送狀態信號之前掛起線程。   
狀態變量通常和互斥體聯系在一起,為了避免競爭狀態出現,一個線程准備等待一個狀態變量之前另外一個線程要先設置好狀態信號。   
pthread_cond_init初始化狀態變量cond,使用cond_attr中定義了的狀態屬性,如果cond_attr為NULL,將會使用默認屬性。LinuxThreads的實現支持沒有任何屬性的cond_attr,因此,cond_attr就是被忽略的。   
pthread_cond_t類型的變量也可以使用PTHREAD_COND_INITIALIZER.常量進行靜態的初始化。   
pthread_cond_signal函數重新開始一個正在等待cond變量的線程。如果沒有線程在等待cond變量,不執行任何操作。如果有多個線程都在等待,某個匹配的線程會被重新開始,但是不一定是哪個。   
pthread_cond_broadcast函數重新開始所有在等待cond變量的線程。如果沒有線程在等待cond變量,不執行任何操作。   
pthread_cond_wait函數對互斥體進行原子的解鎖工作(就像pthread_unlock_mutex),然后等待狀態信號。線程被掛起並不消耗CPU時間,直到發送狀態信號。互斥體必須被調用者鎖定。在返回調用線程之前,互斥鎖被pthread_cond_wait擁有。   
釋放互斥體和在狀態變量上掛起是自動進行的。因此,如果所有的線程經常在狀態信號之前要求互斥體,這會保證在線程在狀態變量上鎖定互斥體的期間狀態變量不會觸發信號。   
pthread_cond_timedwait函數自動釋放互斥體並且等待cond狀態,就像pthread_cond_wait所做的一樣,但是它限制了最大的等待時間。如果cond沒有在一定時間內用abstime中沒有指定的時間做標記,互斥體會重新獲得,然后返回錯誤碼ETIMEOUT。abstime參數指定絕對時間,和time(2)和gettimeofday(2)的一樣:以格林威治時間1970年1月1日零點為起點。   
pthread_cond_destroy函數銷毀狀態變量,釋放它可能持有的資源。沒有線程必須在這里等待狀態變量。在LinuxThreads實現中,狀態變量不與任何資源有關系,所以這個接口除了檢查狀態變量上是否有等待的線程之外不做任何事。   
取消   
pthread_cond_wait和pthread_cond_timedwait都是取消點。如果某個線程在某個這樣的函數中掛起后又被取消,該線程會重新開始執行,然后再鎖定互斥體。(尚未完成!)   
同步信號安全   
狀態函數不是同步安全的,不應該出現在信號處理函數中。特別的,從信號處理函數中調用pthread_cond_signal或pthread_cond_broadcast會導致死鎖。   
返回值   
所有狀態變量函數在成功的時候返回0,在出錯的時候返回出錯碼。   
錯誤碼   
pthread_cond_init, pthread_cond_signal, pthread_cond_broadcast和pthread_cond_wait從來都不會返回出錯碼。   
pthread_cond_timedwait函數在出錯時返回下面的出錯碼:   
ETIMEOUT:狀態變量在abstime限定時間內沒有激發信號。   
EINTR:pthread_cond_timedwait被信號中斷。   
pthread_cond_destroy函數在出錯時返回下面的出錯碼:   
EBUSY:有線程正在cond上等待。   
作者   
Xavier Leroy    
參見   
pthread_condattr_init(3), pthread_mutex_lock(3), pthread_mutex_unlock(3)   
gettimeofday(2), nanosleep(2).   
示例   
考慮兩個共享變量x和y,使用互斥體mut進行保護,一個狀態變量cond在x大於y時激發信號。   
int x,y;   
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;   
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;   
一直等待,直到x大於y:   
pthread_mutex_lock(&mut);   
while (x <= y) {   
pthread_cond_wait(&cond, &mut);   
}   
/* operate on x and y */   
pthread_mutex_unlock(&mut);   
修改x和y可能會使x大於y。如果需要就應該發送信號:   
pthread_mutex_lock(&mut);   
/* modify x and y */   
if (x > y) pthread_cond_broadcast(&cond);   
pthread_mutex_unlock(&mut);   
如果可以證明,至多有一個等待中的線程需要醒來(例如,只有兩個線程,通過x和y聯系起來),pthread_cond_signal可以作為可選的更有效率的輕量級的pthread_cond_broadcast.。如果不能確定,使用pthread_cond_broadcast函數。   
要在5秒鍾內等待x大於y,像下面:   
struct timeval now;   
struct timespec timeout;   
int retcode;   
pthread_mutex_lock(&mut);   
gettimeofday(&now);   
timeout.tv_sec = now.tv_sec + 5;   
timeout.tv_nsec = now.tv_usec * 1000;   
retcode = 0;   
while (x <= y && retcode != ETIMEDOUT) {   
retcode = pthread_cond_timedwait(&cond, &mut, &timeout);   
}   
if (retcode == ETIMEDOUT) {   
/* timeout occurred */   
} else {   
/* operate on x and y */   
}   
pthread_mutex_unlock(&mut);    
    

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM