unix網路程式設計 鎖(一)

2022-04-02 10:23:05 字數 3549 閱讀 7135

閱讀了unix網路程式設計的卷二之後,看著裡面的例項並且理解其原理演算法,就將裡面的c語言的鎖api進行c++封裝以供以後使用。實現的鎖介面以及一些演算法會封裝到我的timepass庫中。我覺得應該就鎖的問題寫乙個系列的部落格。鎖按照其作用域可以分為執行緒鎖和程序鎖; 按照其工作方式:又可以分為互斥鎖,讀寫鎖,檔案鎖。讀寫鎖也是互斥,只是相對於讀寫鎖來說更加精細,其分為讀和寫,讀與讀不會互斥,讀和寫會互斥,寫與寫也會互斥。檔案鎖有相對於讀寫鎖來說更加精細了,對整個檔案,可以分割槽段進行加鎖。

(1) int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex_attr *mutexattr);

初始化mutex; pthreadmutexattrt裡面的shared欄位設定成pthread_process_share,可以通過在共享記憶體裡面建立鎖,實現程序間的互斥鎖。

(2) int pthread_mutex_destroy(pthread_mutext *mutex);

銷毀鎖資源

(3) int pthread_mutex_lock(pthread_mutext *mutex);

獲取鎖的資源,如果已經有程序或者執行緒獲取到了就阻塞掉

(4) int pthread_mutex_unlock(pthread_mutext *mutex);

釋放所資源,在阻塞的程序中或者執行緒中,按照阻塞的佇列順序獲取鎖資源

(5) int pthread_mutex_trylock(pthread_mutext *mutex);

嘗試獲取所資源,如果恰巧所資源被占用,就會返回ebusy的錯誤碼; 其不會像pthread_mutex_lock阻塞掉。這個函式可以用來檢視鎖的占用狀況。

以上如果僅僅是實現互斥鎖的封裝已經夠用了,互斥鎖的類名為mutex,其資料成員如下:

class

mutex

(7) int pthread_cond_init(pthread_condt *cond, pthread_cond_attrt * condattr);

初始化條件資源

(8) int pthread_cond_destroy(pthreadcondt *cond);

銷毀條件資源

(9) int pthread_cond_wait(pthreadcondt *cond, pthreadmutext *mutex);

將mutex與cond進行繫結,當執行wait的時候,首先對mutex進行解鎖,然後再進入阻塞佇列,直到pthreadcondsignal通知,才喚醒; 緊接著占用鎖資源,才向下執行。

(10)int pthreadcondsignal(pthreadcondt *cond);

通過條件資源喚醒互斥鎖

以上通過這些函式可以實現條件鎖:

class condmutex:public

mutex

想象一下,在一條生產線上,多台機器來生產物品,一台機器來打包物品;這其中生產線就是乙個佇列,生產物品的機器就是生產者,打包物品的機器就是消費者。在計算機演算法中,就生產者和消費者而言,生產物品的機器就是生產者,消費物品的機器是消費者。每個生產者分別生產完一次物品,停止下來,讓消費者去消費物品直到消費者消費完所有物品,停下來;生產者再去繼續生產,並且第乙個生產者通知生產線上已經有物品了,讓消費者繼續消費。就這樣不停的往返反覆,生產者和消費者共同去維護乙個佇列,在這過程中,生產者和消費者能夠達到併發。

為什麼不是多個生產者和多個消費者,這樣子速度不是更快麼?

為了維持佇列的順序,生產者和生產者是互斥的,消費者與消費者是互斥的,唯有生產者和消費不互斥。多個生產者確實有它的優勢,當只有乙個生產者的時候,生產線上有了乙個產品之後,生產線停止,讓消費者去消費,這樣子就完全沒有達到消費者和生產者的併發,只是序列的。當生產線上的物品都消耗完了,乙個消費者會解鎖,並且進入等待佇列,這時候可能是另乙個在等待佇列中的消費者獲取到鎖資源,造成這個消費者飢餓消費;其次當生產者生產了物品,去通知消費者消費,要乙個乙個的去通知,即使採用群體喚醒,消費者們是互斥的;況且當消費過程是乙個簡短的過程,乙個執行緒進行消費和多執行緒加鎖進行消費比起來並不會慢,反而加鎖和解鎖會造成效能消耗的。注意只有當消費過程是乙個比較耗時的過程,才會考慮有沒有加鎖的必要。

為什麼多個生產者分別生產一次物品,就會停下來?

畢竟生產者消費者問題並不會像富士康生產線那樣,流水線上兩端的工人步調一致,生產線兩頭的工人不需要互相通知。乙個生產者生產玩一次物品之後,會有乙個通知的過程,為了防止多個執行緒同時通知,造成紊亂,就對通知過程也加鎖了,而這個鎖就是消費用的鎖。當通知過去的時候,消費者會消費完當前物品,直到釋放鎖(消費者消費的過程中一直加鎖解鎖,可以在解鎖的時候,sleep一下,同時也在生產者的過程中sleep一下,可以防止過度的消費或者過度的生產,盡量讓消費者和生產者步調一致,不過sleep的時間不容易把握)。

1

//生產者執行緒函式

2void* produce (void*arg) 9//

往生產線上放資料

10begin_produce();

11produce_unlock();

1213

//這裡的鎖執行速度很快

14consume_lock();

15if

(滿足通知條件)

2021 }

view code

這是生產線程,在producelock裡面,我們還需要判斷生產是否結束,是為了防止這樣的情況發生,當多個生產者執行緒被阻塞了,有乙個執行緒完成了所有的生產任務,如果不判斷,其他的生產線程繼續往下執行,直到這個此次迴圈結束為止,會超出生產的量。

1

//消費者執行緒函式

2void* consume(void*arg)

9begin_consume()

10consume_unlock()11}

12 }

view code

等待生產者通知之所以放到while裡面,是為了防止consume_wait呼叫失敗,造成飢餓消費.

以上是用互斥鎖實現生產者和消費者的思路。在這裡為了方便使用,我實現了乙個四個類,類圖如下:

以上這個uml圖,是用linux下面的dia畫,其完全可以替代visio,而且支援將uml轉化為各種檔案,比如png。

這個生產者和消費者的框架使用起來很簡單,只需要實現乙個類來繼承produceconsume,實現其中的純虛函式。然後啟用執行緒,呼叫threadfuncloader裡面的produce和consume就ok了,使用者不用糾結鎖的問題。

在這裡使用者所要實現的函式有:

produce對應上面的begin_produce

consume對應上面的begin_consume

producecomplete對應上面的「生產結束」

consumecomplete對應上面你的「生產線上沒有了資料"

condition 對應上面的「通知條件」「等待條件」

UNIX網路程式設計 鎖(二)

1.3 訊號量讀寫鎖的實現 此部落格是關於一篇訊號量的文章,訊號量提供程序間互斥,很方便。用mutex來實現訊號量的功能,必須將mutex建立在共享記憶體上才能實現。所以當需要執行緒間互斥的時候,最好是用mutex 當用程序間互斥的時候,用sem。歸結起來,mutex直接用到程序上,顯得無用 sem...

unix網路程式設計(筆記一)

一。1.乙個長時間執行的程式,即守護程序,它只在響應來自網路的請求時才傳送網路訊息。2.通常乙個客和每次只與乙個伺服器通訊,不過以web瀏覽器為例子,該客戶端程式卻可以與多個不同的web伺服器通訊。3.tcp ip 協議簇 也稱為 網際協議簇 4.英特網 和 網際網 網際網路是乙個網際網 網際網是採...

UNIX網路程式設計

在unix network programming 的 3.7 inet pton and inet ntop functions 中提到中有如下兩個巨集定義 define inet addrstrlen 16 for ipv4 dotted decimal define inet6 addrstr...