一、基本概念
競爭與同步:
同乙個程序中的執行緒能共享程序中的絕大多數資源,當它們隨意競爭時可以導致資源會破壞、髒資料、不完整、不一致等問題。
通過一些方法讓程序在競爭資源時相互協調,避免出現資料不完全、不一致等問題,這就叫執行緒同步。
臨界區與臨界資源:
被多個執行緒同時訪問的**叫臨界區,被同時訪問的資源叫臨界資源。
原子操作:中間不會打斷的操作叫原子操作。
二、互斥量(互斥鎖)
pthread_mutex_t 是一種資料型別,可以定義變數。
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
功能:初始化互斥量,也可以使用pthread_mutex_initializer初始化,預設處於開鎖狀態。
int pthread_mutex_lock(pthread_mutex_t *mutex);
功能:對互斥量加鎖,成功則繼續執行,失敗則阻塞,直到互斥量解鎖,才返回。
int pthread_mutex_trylock(pthread_mutex_t *mutex);
功能:嘗試對互斥量加鎖,成功(0)或失敗(ebusy)都立即返回。
int pthread_mutex_unlock(pthread_mutex_t *mutex);
功能:對互斥量解鎖
int pthread_mutex_destroy(pthread_mutex_t *mutex);
功能:銷毀互斥量
三、訊號量
與xsi中的訊號量原理相同,執行緒之間所使用的計數器,用於控制訪問有限的共享資源的執行緒數。
int sem_init(sem_t *sem, int pshared, unsigned int value);
功能:初始化訊號量
sem:被初始化的訊號量
pshared:
0 只能在程序內使用
非0 表示該訊號量可以用共享記憶體的方式,多個程序共享(linux不支援)。
value:訊號量的初始值
int sem_wait(sem_t *sem);
功能:對號量減1,如果不夠減則阻塞
int sem_trywait(sem_t *sem);
功能:對訊號量減1,成功(0)或失敗(eagain)都立即返回
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
功能:對訊號量減,如果不夠減則等待abs_timeout時間,超時後返回(etimedout)。
int sem_post(sem_t *sem);
功能:對訊號量加1。
int sem_destroy(sem_t *sem);
功能:銷毀訊號量
四:死鎖
1、什麼是死鎖
多個程序或執行緒互相等待對方的資源,在得到新的資源之前不會釋放自己的資源,這樣就形成了迴圈等待,這種現象被稱為死鎖。
2、產生死鎖的四大必要條件
資源互斥:資源只有兩種狀態,只有可用和不可用兩狀態,不能同時使用,同一時刻只能被乙個程序或執行緒使用。
占有且請求:已經得到資源的程序或執行緒,繼續請求新的資源,並持續占有舊的資源。
資源不可剝奪:資源已經分配程序或執行緒後,不能被其它程序或執行緒強制性獲取,除非資源的佔有者主動釋放。
環路等待:死鎖發生時,系統中必定有兩個或兩個以上的程序或執行緒組成一條等待環路。
注意:死鎖一旦產生基本無解,現在的作業系統無法解決死鎖,因此只能防止死鎖產生。
3、防止死鎖產生的方法
破壞互斥條件:相辦法讓資源能夠共享使用。
缺點:受環境或資金的影響無法讓資源共享。
破壞占用且請求條件:採用預先靜態分配的方法,程序或執行緒在執行前一次申請所有資源,在資源沒有滿足前不投入執行。
缺點:系統資源會被嚴重浪費,因為有些資源可能開始時使用,而有些資源結束時才使用。
破壞不可剝奪條件:當乙個程序或執行緒已經占有乙個不可剝奪的資源時,請求新資源時無法滿足,則釋放已經占有的資源,一段時間後再重新申請。
缺點:該策略實現起來比較複雜,釋放已經獲取資源可能會導致前一階段的工作失效,反覆的申請釋放資源會增加系統開銷,占用cpu和暫存器、記憶體等資源。
破壞迴圈等待條件:給每個資源進行編號,程序或執行緒按照順序請求資源,只有拿到前一外資源,才能繼續請求下乙個資源。
缺點:資源的編號必須相對穩定,資源新增或銷毀時會受到影響。
演算法:銀行家演算法
4、如何判斷死鎖
1、畫出資源分配圖
2、簡化資源分配圖
3、使用死鎖定理判斷:如果沒有環路肯定不會出現死鎖。
五、條件變數
當某些條件滿足時可以讓執行緒自己可以進入睡眠,也可以在某些條件滿足時可以被其它執行緒喚醒。
int pthread_cond_init(pthread_cond_t cond, pthread_condattr_tcond_attr);
功能:初始化條件變數,也可以使用pthread_cond_initializer。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
功能:讓當前執行緒睡入cond中,並解鎖mutex。
int pthread_cond_signal(pthread_cond_t *cond);
功能:喚醒cond中的乙個執行緒,之前的鎖必須處於開啟狀態,執行緒醒來後會自動把鎖再加上。
int pthread_cond_broadcast(pthread_cond_t *cond);
功能:喚醒cond中的所有執行緒,執行緒醒來時互斥量必須能再次加鎖。
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
功能:讓當前執行緒睡入cond,只睡abstime時間,超時後會自動醒來。
int pthread_cond_destroy(pthread_cond_t *cond);
功能:銷毀條件變數
注意:使用條件變數可以實現生產者與消費者模型。
六、生產者與消費者模型
生產者:產生資料的執行緒
消費者:使用資料的執行緒
倉庫:臨時儲存資料的緩衝區
可能產生的問題:
生產快於消費,倉庫爆滿,撐死。
消費快於生產,倉庫空虛,餓死。
利用條件變數解決問題:
當緩衝區滿的時候,生產線程睡入條件變數(full),通知消費執行緒全部醒來(null)。
當緩衝區空的時候,消費執行緒睡入條件變數(null),通訊生產線程全部醒來(full)。
UNIX環境高階程式設計之第10章 訊號
訊號是軟體中斷.很多比較重要的應用程式都需要處理訊號.訊號提供一種處理非同步時間的方法,例如,終端使用者鍵入中斷鍵,會通過訊號機制停止乙個程式,或及早終止管道中的下乙個程式.首先每個訊號都有乙個名字.這些名字都是以sig開頭.例如,sigabrt是夭折訊號,當程序呼叫abort函式是產生這種訊號.u...
網路程式設計10
accept 發生在三次握手之後。第一次握手 客戶端傳送 syn包 syn j 到伺服器。第二次握手 伺服器收到 syn包,必須確認客戶的 syn ack j 1 同時自己也傳送乙個 ask包 ask k 第三次握手 客戶端收到伺服器的 syn ack包,向伺服器傳送確認包 ack ack k 1 ...
程式設計技巧 10
1.旋轉最好用core animation void startanimation 2.怎麼製作優雅的tableview loading效果 可以在tableviewfooterview裡面設定這個效果,因為顯示出footerview的時候肯定在重新整理資料表之前 hytableviewfooter...