国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

通用線程:POSIX 線程詳解(3)

2019-11-17 05:31:51
字體:
來源:轉載
供稿:網友

  第 3 部分

內容:

條件變量
pthread_cond_wait() 小測驗
初始化和清除
等待
發送信號和廣播
工作組
隊列
data_control 代碼
調試時間
工作組代碼
代碼初排
有關清除的注重事項
創建工作
threadfunc()
join_threads()
結束語
參考資料
關于作者


相關內容:

第 2 部分:稱作互斥對象的小玩意
第 1 部分:POSIX 線程詳解

使用條件變量提高效率
作者:Daniel Robbins


本文是 POSIX 線程三部曲系列的最后一部分,Daniel 將具體討論如何使用條件變量。條件變量是 POSIX 線程結構,可以讓您在碰到某些條件時“喚醒”線程。可以將它們看作是一種線程安全的信號發送。Daniel 使用目前您所學到的知識實現了一個多線程工作組應用程序,本文將圍繞著這一示例而進行討論。

條件變量詳解
在上一篇文章結束時,我描述了一個比較非凡的難題:假如線程正在等待某個特定條件發生,它應該如何處理這種情況?它可以重復對互斥對象鎖定和解鎖,每次都會檢查共享數據結構,以查找某個值。但這是在浪費時間和資源,而且這種繁忙查詢的效率非常低。解決這個問題的最佳方法是使用 pthread_cond_wait() 調用來等待非凡條件發生。

了解 pthread_cond_wait() 的作用非常重要 -- 它是 POSIX 線程信號發送系統的核心,也是最難以理解的部分。

首先,讓我們考慮以下情況:線程為查看已鏈接列表而鎖定了互斥對象,然而該列表恰巧是空的。這一特定線程什么也干不了 -- 其設計意圖是從列表中除去節點,但是現在卻沒有節點。因此,它只能:

鎖定互斥對象時,線程將調用 pthread_cond_wait(&mycond,&mymutex)。pthread_cond_wait() 調用相當復雜,因此我們每次只執行它的一個操作。

pthread_cond_wait() 所做的第一件事就是同時對互斥對象解鎖(于是其它線程可以修改已鏈接列表),并等待條件 mycond 發生(這樣當 pthread_cond_wait() 接收到另一個線程的“信號”時,它將清醒)。現在互斥對象已被解鎖,其它線程可以訪問和修改已鏈接列表,可能還會添加項。

此時,pthread_cond_wait() 調用還未返回。對互斥對象解鎖會立即發生,但等待條件 mycond 通常是一個阻塞操作,這意味著線程將睡眠,在它清醒之前不會消耗 CPU 周期。這正是我們期待發生的情況。線程將一直睡眠,直到特定條件發生,在這期間不會發生任何浪費 CPU 時間的繁忙查詢。從線程的角度來看,它只是在等待 pthread_cond_wait() 調用返回。

現在繼續說明,假設另一個線程(稱作“2 號線程”)鎖定了 mymutex 并對已鏈接列表添加了一項。在對互斥對象解鎖之后,2 號線程會立即調用函數 pthread_cond_broadcast(&mycond)。此操作之后,2 號線程將使所有等待 mycond 條件變量的線程立即清醒。這意味著第一個線程(仍處于 pthread_cond_wait() 調用中)現在將清醒。

現在,看一下第一個線程發生了什么。您可能會認為在 2 號線程調用 pthread_cond_broadcast(&mymutex) 之后,1 號線程的 pthread_cond_wait() 會立即返回。不是那樣!實際上,pthread_cond_wait() 將執行最后一個操作:重新鎖定 mymutex。一旦 pthread_cond_wait() 鎖定了互斥對象,那么它將返回并答應 1 號線程繼續執行。那時,它可以馬上檢查列表,查看它所感愛好的更改。

停止并回顧!
那個過程非常復雜,因此讓我們先往返顧一下。第一個線程首先調用:



pthread_mutex_lock(&mymutex);




然后,它檢查了列表。沒有找到感愛好的東西,于是它調用:



pthread_cond_wait(&mycond, &mymutex);





然后,pthread_cond_wait() 調用在返回前執行許多操作:



pthread_mutex_unlock(&mymutex);




它對 mymutex 解鎖,然后進入睡眠狀態,等待 mycond 以接收 POSIX 線程“信號”。一旦接收到“信號”(加引號是因為我們并不是在討論傳統的 UNIX 信號,而是來自 pthread_cond_signal() 或 pthread_cond_broadcast() 調用的信號),它就會清醒。但 pthread_cond_wait() 沒有立即返回 -- 它還要做一件事:重新鎖定 mutex:



pthread_mutex_lock(&mymutex);




pthread_cond_wait() 知道我們在查找 mymutex “背后”的變化,因此它繼續操作,為我們鎖定互斥對象,然后才返回。

pthread_cond_wait() 小測驗
現在已回顧了 pthread_cond_wait() 調用,您應該了解了它的工作方式。應該能夠敘述 pthread_cond_wait() 依次執行的所有操作。嘗試一下。假如理解了 pthread_cond_wait(),其余部分就相當輕易,因此請重新閱讀以上部分,直到記住為止。好,讀完之后,能否告訴我在調用 pthread_cond_wait() 之前,互斥對象必須處于什么狀態?pthread_cond_wait() 調用返回之后,互斥對象處于什么狀態?這兩個問題的答案都是“鎖定”。既然已經完全理解了 pthread_cond_wait() 調用,現在來繼續研究更簡單的東西 -- 初始化和真正的發送信號和廣播進程。到那時,我們將會對包含了多線程工作隊列的 C 代碼了如指掌。

初始化和清除
條件變量是一個需要初始化的真實數據結構。以下就初始化的方法。首先,定義或分配一個條件變量,如下所示:




pthread_cond_t mycond;




然后,調用以下函數進行初始化:




pthread_cond_init(&mycond,NULL);




瞧,初始化完成了!在釋放或廢棄條件變量之前,需要毀壞它,如下所示:




pthread_cond_destroy(&mycond);




很簡單吧。接著討論 pthread_cond_wait() 調用。

等待
一旦初始化了互斥對象和條件變量,就可以等待某個條件,如下所示:




pthread_cond_wait(&mycond, &mymutex);




請注重,代碼在邏輯上應該包含 mycond 和 mymutex。一個特定條件只能有一個互斥對象,而且條件變量應該表示互斥數據“內部”的一種非凡的條件更改。一個互斥對象可以用許多條件變量(例如,cond_empty、cond_full、cond_cleanup),但每個條件變量只能有一個互斥對象。

發送信號和廣播
對于發送信號和廣播,需要注重一點。假如線程更改某些共享數據,而且它想要喚醒所有正在等待的線程,則應使用 pthread_cond_broadcast 調用,如下所示:




pthread_cond_broadcast(&mycond);




在某些情況下,活動線程只需要喚醒第一個正在睡眠的線程。假設您只對隊列添加了一個工作作業。那么只需要喚醒一個工作程序線程(再喚醒其它線程是不禮貌的!):




pthread_cond_signal(&mycond);




此函數只喚醒一個線程。假如 POSIX 線程標準答應指定一個整數,可以讓您喚醒一定數量的正在睡眠的線程,那就更完美了。但是很可惜,我沒有被邀請參加會議。

工作組
我將演示如何創建多線程工作組。在這個方案中,我們創建了許多工作程序線程。每個線程都會檢查 wq(“工作隊列”),查看是否有需要完成的工作。假如有需要完成的工作,那么線程將從隊列中除去一個節點,執行這些特定工作,然后等待新的工作到達。

與此同時,主線程負責創建這些工作程序線程、將工作添加到隊列,然后在它退出時收集所有工作程序線程。您將會碰到許多 C 代碼,好好預備吧!

隊列
需要隊列是出于兩個原因。首先,需要隊列來保存工作作業。還需要可用于跟蹤已終止線程的數據結構。還記得前幾篇文章(請參閱本文結尾處的參考資料)中,我曾提到過需要使用帶有特定進程標識的 pthread_join 嗎?使用“清除隊列”(稱作 "cq")可以解決無法等待任何已終止線程的問題(稍后將具體討論這個問題)。以下是標準隊列代碼。將此代碼保存到文件 queue.h 和 queue.c:

queue.h
/* queue.h
** Copyright 2000 Daniel Robbins, Gentoo Technologies, Inc.

** Author: Daniel Robbins
** Date: 16 Jun 2000
*/

typedef strUCt node {
struct node *next;
} node;


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 太湖县| 大石桥市| 加查县| 平泉县| 临高县| 小金县| 澄江县| 和顺县| 达拉特旗| 郓城县| 灵川县| 寿光市| 闽清县| 根河市| 东乡| 武平县| 黎川县| 焦作市| 北辰区| 郴州市| 建昌县| 通许县| 维西| 莲花县| 绥德县| 育儿| 宜昌市| 施秉县| 临汾市| 张家港市| 江门市| 察雅县| 保康县| 肃南| 胶州市| 安丘市| 高唐县| 卓尼县| 抚顺市| 崇义县| 衡阳县|