第十三周学习报告
第十二章 并發(fā)編程
如果邏輯控制流在時(shí)間上重疊,那么它們就是并發(fā)的。
使用應(yīng)用級(jí)并發(fā)的應(yīng)用程序稱為并發(fā)程序,三種基本的構(gòu)造并發(fā)程序的方法:進(jìn)程、I/O多路復(fù)用、線程
12.1基于進(jìn)程的并發(fā)編程
第一步:服務(wù)器接受客戶端的連接請(qǐng)求
第二步:服務(wù)器派生一個(gè)子程序?yàn)檫@個(gè)客戶端服務(wù)
第三步:服務(wù)器接受另一個(gè)連接請(qǐng)求
第四步:服務(wù)器派生另一個(gè)子程序?yàn)樾碌目蛻舳朔?wù)
12.1.1 基于進(jìn)程的并發(fā)服務(wù)器
必須要包括一個(gè)SIGCHLD處理程序,來回收僵死子程序的資源
為避免存儲(chǔ)器泄露,必須關(guān)閉各自的connfd拷貝
直到父子進(jìn)程的connfd都關(guān)閉了,到客戶端的的連接才會(huì)終止
12.1.2 關(guān)于進(jìn)程的優(yōu)劣
父子進(jìn)程間的共享狀態(tài)信息模型:共享文件表,但是不共享用戶地址信息
有獨(dú)立的地址空間:優(yōu)點(diǎn):一個(gè)進(jìn)程不可能不小心覆蓋另一個(gè)進(jìn)程的虛擬存儲(chǔ)器
缺點(diǎn):共享狀態(tài)信息變得困難,必須使用顯式的IPC機(jī)制;比較慢
?
12.2 基于I/O多路復(fù)用的并發(fā)編程
服務(wù)器必須響應(yīng)兩個(gè)相互獨(dú)立的I/O事件
基本思路:使用select函數(shù),要求內(nèi)核掛起進(jìn)程
Select函數(shù)有兩個(gè)輸入:1.讀集合的描述符集合 2.基數(shù)n
當(dāng)且僅當(dāng)一個(gè)從該描述符讀取一個(gè)字節(jié)的請(qǐng)求不會(huì)阻塞時(shí),描述符k就表示準(zhǔn)備好可以讀了
12.2.1 基于I/多路復(fù)用的并發(fā)事件驅(qū)動(dòng)服務(wù)器
I/O多路復(fù)用可以用做并發(fā)事件驅(qū)動(dòng)程序的基礎(chǔ)
一個(gè)狀態(tài)機(jī)就是一組狀態(tài)、輸入事件和轉(zhuǎn)移
自循環(huán)是同一輸入和輸出狀態(tài)之間的轉(zhuǎn)移
活動(dòng)客戶端的集合維護(hù)在一個(gè)pool結(jié)構(gòu)里
在通過調(diào)用init_pool初始化池之后,服務(wù)器進(jìn)入一個(gè)無限循環(huán)
在循環(huán)的每次迭代中,服務(wù)器調(diào)用select函數(shù)來檢測兩種不同類型的輸入事件:
Init_pool函數(shù)初始化客戶端池
Add_client函數(shù)添加一個(gè)新的客戶端到活動(dòng)客戶端池中
Check_clients函數(shù)回送來自每個(gè)準(zhǔn)備好的已連接描述符的一個(gè)文本行
優(yōu)點(diǎn):1.比基于進(jìn)程的設(shè)計(jì)給了程序員更多對(duì)程序行為的控制
2.每個(gè)邏輯流都能訪問該進(jìn)程的全部地址空間
缺點(diǎn):1.編碼復(fù)雜 2.不能充分利用多核處理器
?
12.3基于線程的并發(fā)編程
線程就是運(yùn)行在進(jìn)程上下文中的邏輯流
每個(gè)線程都有它自己的線程上下文,包括一個(gè)唯一的整數(shù)線程ID、棧、棧指針、程序計(jì)數(shù)器、通用目的寄存器和條件碼
所有運(yùn)行在一個(gè)進(jìn)程里的線程共享該進(jìn)程的整個(gè)虛擬地址空間
12.3.1線程執(zhí)行模型
每個(gè)進(jìn)程開始生命周期時(shí)都是單一線程,這個(gè)線程稱為主線程
在某一時(shí)刻,線程創(chuàng)建一個(gè)對(duì)等線程,從這個(gè)時(shí)間點(diǎn)開始,兩個(gè)線程就并發(fā)地運(yùn)行
最后,因?yàn)橹骶€程執(zhí)行一個(gè)慢速系統(tǒng)調(diào)用,控制就會(huì)通過上下文切換傳遞到對(duì)等線程
對(duì)等線程執(zhí)行一段時(shí)間,然后控制傳遞回主線程
12.3.2Posix線程
Posix線程是在C程序中處理線程的一個(gè)標(biāo)準(zhǔn)接口
Pthreads運(yùn)行程序創(chuàng)建、殺死和回收線程,與對(duì)等線程安全地共享數(shù)據(jù)
12.3.3創(chuàng)建線程
Pthread_create函數(shù)
創(chuàng)建一個(gè)新的線程,并帶著一個(gè)輸入變量arg
在新線程的上下文中運(yùn)行線程例程f
當(dāng)其返回時(shí),參數(shù)tid包含新創(chuàng)建線程的ID
12.3.4終止線程
方法:1.頂端線程例程返回(隱式)
2.調(diào)用pthread_exit函數(shù)(顯式)
3.某個(gè)對(duì)等線程調(diào)用Unix的exit函數(shù)
4.另一個(gè)對(duì)等線程通過以當(dāng)前線程ID作為參數(shù)調(diào)用pthread_cancle函數(shù)
12.3.5 回收已終止線程的資源
調(diào)用pthread_join函數(shù)等待其他線程終止
會(huì)阻塞,直到線程tid終止,將線程例程返回的(void*)指針賦值為thread_return指向的位置,然后回收已終止線程占用的所有存儲(chǔ)器資源
12.3.6分離線程
Pthread_detach分離可結(jié)合線程tid
線程能夠通過以pthread_self()為參數(shù)的pthread_detach調(diào)用來分離它們
12.3.7 初始化進(jìn)程
Pthread_once
?
12.4多線程程序中的共享變量
12.4.1 線程存儲(chǔ)器模型
一組并發(fā)進(jìn)程運(yùn)行在一個(gè)進(jìn)程的上下文中
每個(gè)線程都有它自己獨(dú)立的線程上下文
12.4.2 將變量映射到存儲(chǔ)器
全局變量是定義在函數(shù)之外的變量
本地自動(dòng)變量就是定義在函數(shù)內(nèi)部但是沒有static屬性的變量
本地靜態(tài)變量是定義在函數(shù)內(nèi)部并有static屬性的變量
12.4.3 共享變量
一個(gè)變量v是共享的,當(dāng)且僅當(dāng)它的一個(gè)實(shí)例被一個(gè)以上的變量引用
?
12.5 用信號(hào)量同步線程
一般而言,沒有辦法預(yù)測操作系統(tǒng)是否將為線程選擇一個(gè)正確的順序,可以借助進(jìn)度圖來闡明
12.5.1 進(jìn)度圖
進(jìn)度圖將n個(gè)并發(fā)線程的執(zhí)行模型化為一條n維笛卡兒空間中的軌跡線
每條軸k對(duì)應(yīng)于進(jìn)程k的進(jìn)度
每個(gè)點(diǎn)I代表進(jìn)程已經(jīng)完成了指令I(lǐng)這一狀態(tài)
圖的原點(diǎn)對(duì)應(yīng)于沒有任何線程完成一條指令的初始狀態(tài)
進(jìn)度圖將指令執(zhí)行模型化為一種狀態(tài)到另一種狀態(tài)的轉(zhuǎn)換
合法的轉(zhuǎn)換是向右或者向上的
操作共享變量cnt內(nèi)容的指令(L,U,S)構(gòu)成了一個(gè)臨界區(qū)
兩個(gè)臨界區(qū)的交集稱為不安全區(qū)
繞開不安全區(qū)的軌跡線叫做安全軌跡線,反之,叫做不安全軌跡線
?
12.5.2 信號(hào)量
信號(hào)量s是具有非負(fù)整數(shù)的全局變量,只能由兩種操作處理。
P(s):如果s是非零的,那么P將s減1返回,如果s為零,就掛起
V(s):將s加1,如果有任何線程阻塞在P操作等待s變成非零,那么V操作會(huì)重啟線程中的一個(gè),然后s減1
?
12.5.3 使用信號(hào)量來實(shí)現(xiàn)互斥
基本思想:將每個(gè)共享變量與一個(gè)信號(hào)量s聯(lián)系起來,用P和V操作將臨界區(qū)包圍起來
二元信號(hào)量的值總是0或1
以提供互斥為目的的信號(hào)量也稱為互斥鎖
P:加鎖 V:解鎖
一個(gè)被用作一組可用資源的計(jì)數(shù)器的信號(hào)量稱為計(jì)數(shù)信號(hào)量
關(guān)鍵思想:創(chuàng)建禁止區(qū)
?
12.7 其他并發(fā)問題
12.7.1 線程安全
四個(gè)線程不安全函數(shù)類:
12.7.2 可重入性
可重入函數(shù):當(dāng)它們被多個(gè)線程調(diào)用時(shí),不會(huì)引用任何共享數(shù)據(jù)
12.7.3 在線程化的程序中使用已存在的庫函數(shù)
見p693圖12-39
除了rand和strtok,所以這些線程不安全函數(shù)都是第3類的
12.7.4 競爭
當(dāng)一個(gè)程序的正確性依賴于一個(gè)線程要在另一個(gè)線程到達(dá)y點(diǎn)之前到達(dá)它的控制流中的x點(diǎn),就會(huì)發(fā)生競爭
12.7.5 死鎖
信號(hào)量引入運(yùn)行時(shí)的錯(cuò)誤,叫做死鎖
一組線程被阻塞,等待一個(gè)永遠(yuǎn)也不會(huì)為真的條件
互斥鎖加鎖順序規(guī)則:如果對(duì)于程序中每對(duì)互斥鎖(s,t),給所有的鎖分配一個(gè)全序,每個(gè)線程按照這個(gè)順序來請(qǐng)求鎖,并且按照逆序來釋放,那么這個(gè)程序就是無死鎖的。
參考資料:《深入理解計(jì)算機(jī)系統(tǒng)》
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/javablack/p/5024192.html
總結(jié)
- 上一篇: scala类型推断及库方法设计原则和==
- 下一篇: 1209.1——快速排序算法