#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pthread.h> typedef struct ct_sum { int sum; pthread_mutex_t lock; } ct_sum; void * add1(void * cnt) { pthread_mutex_lock(&(((ct_sum*) cnt)->lock)); int i; for (i = 0; i < 50; i++) { (*(ct_sum*) cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*) cnt)->lock)); pthread_exit(NULL); return 0; } void * add2(void *cnt) { int i; cnt = (ct_sum*) cnt; pthread_mutex_lock(&(((ct_sum*) cnt)->lock)); for (i = 50; i < 101; i++) { (*(ct_sum*) cnt).sum += i; } pthread_mutex_unlock(&(((ct_sum*) cnt)->lock)); pthread_exit(NULL); return 0; } int main(void) { int i; pthread_t ptid1, ptid2; int sum = 0; ct_sum cnt; pthread_mutex_init(&(cnt.lock), NULL); cnt.sum = 0; pthread_create(&ptid1, NULL, add1, &cnt); pthread_create(&ptid2, NULL, add2, &cnt); pthread_mutex_lock(&(cnt.lock)); printf("sum %d\n", cnt.sum); pthread_mutex_unlock(&(cnt.lock)); pthread_join(ptid1, NULL); pthread_join(ptid2, NULL); pthread_mutex_destroy(&(cnt.lock)); return 0; }
linux下爲了多線程同步,一般用到鎖的概念。html
互斥鎖是一種經過簡單的加鎖的方法來控制對共享資源的存取,用於解決線程間資源訪問的惟一性問題。互斥鎖有上鎖和解鎖兩種狀態,在同一時刻只能有一個線程掌握某個互斥的鎖,擁有上鎖狀態的線程能夠對共享資源進行操做。若其餘線程但願對一個已經上了鎖的互斥鎖上鎖,則該線程會被掛起,直到上鎖的線程釋放掉互斥鎖爲止。linux
posix下抽象了一個鎖類型的結構:ptread_mutex_t。經過對該結構的操做,來判斷資源是否能夠訪問。顧名思義,加鎖(lock)後,別人就沒法打開,只有當鎖沒有關閉(unlock)的時候才能訪問資源。
它主要用以下5個函數進行操做。
1:pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t *attr); 初始化鎖變量mutex。attr爲鎖屬性,NULL值爲默認屬性。
2:pthread_mutex_lock(pthread_mutex_t *mutex);加鎖
3:pthread_mutex_tylock(pthread_mutex_t *mutex);加鎖,可是與2不同的是當鎖已經在使用的時候,返回爲EBUSY,而不是掛起等待。
4:pthread_mutex_unlock(pthread_mutex_t *mutex);釋放鎖安全
5:pthread_mutex_destroy(pthread_mutex_t *mutex);使用完後釋放多線程
動態方式是採用pthread_mutex_init()函數來初始化互斥鎖,API定義以下: int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr) 其中mutexattr用於指定互斥鎖屬性(見下),若是爲NULL則使用缺省屬性。 有兩種方法建立互斥鎖,靜態方式和動態方式。POSIX定義了一個宏PTHREAD_MUTEX_INITIALIZER來靜態初始化互斥鎖,方法以下: pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; 在LinuxThreads實現中,pthread_mutex_t是一個結構,而PTHREAD_MUTEX_INITIALIZER則是一個結構常量。異步
pthread_mutex_destroy ()用於註銷一個互斥鎖,API定義以下: int pthread_mutex_destroy(pthread_mutex_t *mutex) 銷燬一個互斥鎖即意味着釋放它所佔用的資源,且要求鎖當前處於開放狀態。因爲在Linux中,互斥鎖並不佔用任何資源,所以LinuxThreads中的 pthread_mutex_destroy()除了檢查鎖狀態之外(鎖定狀態則返回EBUSY)沒有其餘動做。函數
* PTHREAD_MUTEX_TIMED_NP,這是缺省值,也就是普通鎖。當一個線程加鎖之後,其他請求鎖的線程將造成一個等待隊列,並在解鎖後按優先級得到鎖。這種鎖策略保證了資源分配的公平性。 互斥鎖的屬性在建立鎖的時候指定,在LinuxThreads實現中僅有一個鎖類型屬性,不一樣的鎖類型在試圖對一個已經被鎖定的互斥鎖加鎖時表現不一樣。當前(glibc2.2.3,linuxthreads0.9)有四個值可供選擇:測試
* PTHREAD_MUTEX_RECURSIVE_NP,嵌套鎖,容許同一個線程對同一個鎖成功得到屢次,並經過屢次unlock解鎖。若是是不一樣線程請求,則在加鎖線程解鎖時從新競爭。spa
* PTHREAD_MUTEX_ERRORCHECK_NP,檢錯鎖,若是同一個線程請求同一個鎖,則返回EDEADLK,不然與PTHREAD_MUTEX_TIMED_NP類型動做相同。這樣就保證當不容許屢次加鎖時不會出現最簡單狀況下的死鎖。線程
* PTHREAD_MUTEX_ADAPTIVE_NP,適應鎖,動做最簡單的鎖類型,僅等待解鎖後從新競爭。nuxt
int pthread_mutex_lock(pthread_mutex_t *mutex) 鎖操做主要包括加鎖pthread_mutex_lock()、解鎖pthread_mutex_unlock()和測試加鎖 pthread_mutex_trylock()三個,不論哪一種類型的鎖,都不可能被兩個不一樣的線程同時獲得,而必須等待解鎖。對於普通鎖和適應鎖類型,解鎖者能夠是同進程內任何線程;而檢錯鎖則必須由加鎖者解鎖纔有效,不然返回EPERM;對於嵌套鎖,文檔和實現要求必須由加鎖者解鎖,但實驗結果代表並無這種限制,這個不一樣目前尚未獲得解釋。在同一進程中的線程,若是加鎖後沒有解鎖,則任何其餘線程都沒法再得到鎖。
int pthread_mutex_unlock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
pthread_mutex_trylock()語義與pthread_mutex_lock()相似,不一樣的是在鎖已經被佔據時返回EBUSY而不是掛起等待。
這個鎖機制同時也不是異步信號安全的,也就是說,不該該在信號處理過程當中使用互斥鎖,不然容易形成死鎖。POSIX 線程鎖機制的Linux實現都不是取消點,所以,延遲取消類型的線程不會因收到取消信號而離開加鎖等待。值得注意的是,若是線程在加鎖後解鎖前被取消,鎖將永遠保持鎖定狀態,所以若是在關鍵區段內有取消點存在,或者設置了異步取消類型,則必須在退出回調函數中解鎖。
互斥鎖屬性使用互斥鎖(互斥)可使線程按順序執行。一般,互斥鎖經過確保一次只有一個線程執行代碼的臨界段來同步多個線程。互斥鎖還能夠保護單線程代碼。
互斥鎖的一個明顯缺點是它只有兩種狀態:鎖定和非鎖定。而條件變量經過容許線程阻塞和等待另外一個線程放鬆信號的方法彌補了互斥鎖的不足,它常和互斥鎖一塊使用。使用時,條件變量被用來阻塞一個線程,當條件不知足時,線程每每解開相應的互斥鎖並等待條件發生變化。一旦其餘的某個線程改變了條件變量,它將通知相應的條件變量喚醒一個或多個正在被此條件阻塞的線程。這些線程將從新鎖定互斥鎖並從新測試條件是否知足。條件變量上的基本操做有兩個。1.觸發條件:當條件變爲true時;2.等待條件:掛起線程直到其餘線程觸發條件。條件變量的數據類型是pthreead_cond_t,在使用前也須要初始化。