一、使用互斥鎖
1、初始化互斥量
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;//靜態初始化互斥量 int pthread_mutex_init(pthread_mutex_t*mutex,pthread_mutexattr_t*attr);//動態初始化互斥量 int pthread_mutex_destory(pthread_mutex_t*mutex);//撤銷互斥量
不能拷貝互斥量變量,但可以拷貝指向互斥量的指針,這樣就可以使多個函數或線程共享互斥量來實現同步。上面動態申請的互斥量需要動態的撤銷。
2、加鎖和解鎖互斥量
int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_trylock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t*mutex);
當調用pthread_mutex_lock加鎖互斥量時,如果此時互斥量已經被鎖住,則調用線程將被阻塞。而pthread_mutex_trylock函數當調用互斥量已經被鎖住時調用該函數將返回錯誤代碼EBUSY。使用和信號量一樣,先鎖住互斥量再處理共享數據,最後解鎖互斥量。
針對上信號量中的示例進行修改得:
#include<pthread.h> #include<stdio.h> #include<semaphore.h> #define NITERS 100000000 /*共享變量*/ unsigned int cnt = 0; //sem_t mutex; pthread_mutex_t mutex; void *count(void *arg) { int i; for(i=0;i<NITERS;i++) { pthread_mutex_lock(&mutex); cnt++; pthread_mutex_unlock(&mutex); } return arg; } int main() { pthread_t tid1,tid2; int status; pthread_mutex_init(&mutex,NULL); pthread_mutex_destroy(&mutex); if(cnt!=(unsigned)NITERS*2) printf("Boom!,cnt=%d\n",cnt); else printf("Ok cnt=%d\n",cnt); return 0; }
3、使用多個互斥量
使用多個互斥量可能造成死鎖問題。如下:
線程1 線程2 pthread_mutex_lock(&mutex_a); pthread_mutex_lock(&mutex_b); pthread_mutex_lock(&mutex_b); pthread_mutex_lock(&mutex_a);
當兩個線程都完成第一步時,都無法完成第二步,將造成死鎖。可以通過以下兩種方法來避免死鎖:
固定加鎖層次:所有需要同時加鎖互斥量A和互斥量B的代碼,必須先加鎖A再加鎖B。
試加鎖和回退:在鎖住第一個互斥量後,使用pthread_mutex_trylock來加鎖其他互斥量,如果失敗則將已加鎖的互斥量釋放,並重新加鎖。
查看本欄目更多精彩內容:http://www.bianceng.cn/OS/unix/
二、使用讀寫鎖
通過讀寫鎖,可以對受保護的共享資源進行並發讀取和獨占寫入。讀寫鎖是可以在讀取或寫入模式下鎖定的單一實體。要修改資源,線程必須首先獲取互斥寫鎖。必須釋放所有讀鎖之後,才允許使用互斥寫鎖。
1. 初始化和銷毀:
#include <pthread.h> int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
同互斥量一樣, 在釋放讀寫鎖占用的內存之前, 需要先通過pthread_rwlock_destroy對讀寫鎖進行清理工作, 釋放由init分配的資源.
2.加鎖和解鎖
讀取讀寫鎖中的鎖 int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); 讀取非阻塞讀寫鎖中的鎖 int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 寫入讀寫鎖中的鎖 int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); 寫入非阻塞讀寫鎖中的鎖 int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 解除鎖定讀寫鎖 int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
三、條件變量
假如某個線程需要等待系統處於某種狀態下才能繼續執行,Linux為了解決這種問題引入了條件變量這種線程同步對象,條件變量是用來通知共享數據狀態信息的,等待條件變量總是返回鎖住的互斥量,條件變量是與互斥量相關、也與互斥量保護的共享數據相關的信號機制。條件變量不提供互斥,需要一個互斥量來同步對共享數據的訪問,這就是為什麼在等待條件變量時必須指定一個互斥量。
1、創建和銷毀條件變量
#include <pthread.h> pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond);
2、等待條件變量
#include <pthread.h> int pthread_cond_timedwait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex,const struct timespec *restrict abstime); int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
兩個函數的差別在於前者指定一個超時時間,在該時間內阻塞調用線程,並等待條件變量,如果規定時間內條件還沒有發生,則函數返回。每個條件變量必須一個特定互斥量關聯,當線程等待條件變量時,他必須將相關互斥量鎖住。在阻塞線程之前,條件變量等待操作將解鎖互斥量,而在重新返回線程之前,會在次鎖住互斥量。
3、喚醒條件變量等待線程
#include <pthread.h> int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal將會激活等待線程中的一個;pthread_cond_broadcast將會激活所有的線程。另外請注意這兩個函數也需要互斥量來保護。
作者:csdn博客 ctthuangcheng