1. 程式人生 > >Boost.thread 同步鎖詳解

Boost.thread 同步鎖詳解

參考 

http://patmusing.blog.163.com/blog/static/1358349602010183920489/ 

標準C++執行緒即將來臨,而且將會從Boost Threads發展而來,研究一下由Boost Threads作者寫的這篇文章吧。

重要更新

Boost Threads更新方面的情況,請看Anthony Williams的文章,他是Boost Threads維護人員,該文發表於Dr. Dobb’s Journal200811月份的刊物上。

就在幾年前,寫一個多執行緒的程式還是不太常見的事情[1],而今天網際網路伺服器應用已經可以執行多執行緒應用,高效地處理多客戶端的連結。為了提高吞吐量,交易伺服器用獨立的執行緒提供服務,

GUI應用程式也將耗時的操作分離開來,以使得介面本身能夠更加及時地做出反應,等等。

C++標準並未提及執行緒,這就讓程式設計師們感到疑惑:寫多執行緒的C++程式到底是否可行?儘管不能寫符合標準的多執行緒程式[2],程式設計師們還是可以通過作業系統提供的庫函式來寫多執行緒程式,如果那個作業系統支援執行緒的話。但這樣做至少存在兩個問題:這些庫幾乎全部是用C寫的,因此在C++中使用需要格外小心;另外,每個作業系統都僅僅提供自己的多執行緒處理方面的支援。由此,最終的程式碼既非標準的,也不可移植。Boost.Threads正是為了解決這兩個問題而設計的。

Boost是一個由C++標準委員會庫函式工作組相關成員發起的一個組織,旨在為

C++開發出新的程式碼庫。目前大約有2000名成員。在Boost程式碼釋出版本中可以找到許多有用的庫,Boost.Threads的出現,就是為了讓這些庫更加執行緒安全。

許多C++專家對Boost.Threads的設計提出了寶貴意見。所有介面都是重新設計,而非簡單地將C執行緒的API進行封裝。許多C++特性(諸如建構函式/解構函式,函式物件和模板等)被廣泛採用,使得介面更加靈活。當前版本支援POSIXWin32Macintosh Carbon等平臺。

執行緒建立

boost::thread類代表一個執行執行緒(a thread of execution),就像std::fstream

類代表一個檔案一樣。預設建構函式建立一個代表當前執行執行緒的一個例項。過載建構函式則有一個函式物件[3]作為引數,該函式物件沒有實參(argument),也無返回值。過載的建構函式建立一個新的執行緒,然後呼叫函式物件。

初看起來,這種設計不如用典型的C方法來建立執行緒那麼有用,因為典型的C方法建立執行緒,可以向新執行緒呼叫的函式傳入一個void指標,而這個指標用來傳遞資料。不過,由於Boost.Threads採用了函式物件,而不是函式指標,因此函式物件攜帶執行緒要用到的資料是完全可以的。這種方法更加靈活,而且型別安全。如果再和相關的函式庫結合起來,比如Boost.Bind,這種方式可以讓你輕鬆地將任意多的資料傳遞給新建立的執行緒。

目前,我們還不能對用Boost.Threads建立的執行緒物件做太多的運算。實際上,只可以執行兩種操作。一、執行緒物件可以用==!=來比較兩者是否相等或不相等,用以判斷兩個物件是否指向同一個執行緒;二、呼叫boost::thread::join以等待執行緒結束。其他一些庫,或許允許你做另外一些操作(例如,設定或者清除執行緒的優先順序等)。因為這些操作要對映到一個可移植的庫介面中並不是一件容易的事情,決定如何將此類操作加入到Boost.Threads中的研究工作,目前正在進行當中。

列表1說明了boost::thread類的一個非常簡單的用法。其中建立了一個新的執行緒,該執行緒簡單地向std::cout輸出“Hello World”,然後main執行緒等待它的結束。

#include <boost/thread/thread.hpp>

#include <iostream>

void hello()

{

         std::cout << "Hello world, I'm a thread!" << std::endl;

}

int main(int argc, char* argv[])

{

         boost::thread thrd(&hello);                  // 譯註:hello前面的&符號,可要可不要

         thrd.join();

         return 0;

}

列表1

互斥體(Mutexes)

寫過多執行緒程式的人都知道,不能讓多個執行緒同時訪問共享的資源是至關重要的。如果一個執行緒試圖改變共享資料的值,而另外一個執行緒試圖去讀取該共享資料的值,結果將是未定義的。為了阻止這樣的事情發生,需要用到一些特殊的原始資料型別和操作。其中最重的一個就是總所周知的mutex(“mutual exclusion”的縮寫。譯註:相互排斥的意思,經常被翻譯為互斥體”)mutex在同一時間只能允許一個執行緒訪問共享資源。當一個執行緒需要訪問共享資源時,它必須先鎖住”mutex,如果任何其他執行緒已經鎖住了mutex,那麼本操作將會一直被阻塞,直到鎖住了mutex的執行緒解鎖,這就保證了共享資源,在同一時間,只有一個執行緒可以訪問。

mutex的概念有幾個變種。Boost.Threads支援兩大型別的mutex:簡單mutex和遞迴mutex。一個簡單的mutex只能被鎖住一次,如果同一執行緒試圖兩次鎖定mutex,將會產生死鎖。對於遞迴mutex,一個執行緒可以多次鎖定一個mutex,但必須以同樣的次數對mutex進行解鎖,否則其他執行緒將無法鎖定該mutex

在上述兩大類mutex的基礎上,一個執行緒如何鎖定一個mutex也有些不同變化。一個執行緒有3種可能方法來鎖定mutex

1. 等待並試圖對mutex加鎖,直到沒有其他執行緒鎖定mutex

2. 試圖對mutex加鎖,並立即返回,如果其他執行緒鎖定了mutex

3. 等待並試圖對mutex加鎖,直到沒有其他執行緒鎖定mutex或者直到規定的時間已過。

看起來最好的mutex型別是遞迴的mutex了,因為上述3種加鎖的方式它都支援。不過,不同的加鎖方式有不同的消耗,因此對於特定的應用,Boost.Threads允許你挑選最有效率的mutex。為此,Boost.Threads提供了6中型別的mutex,效率由高到低排列:boost::mutexboost::try_mutexboost::timed_mutexboost::recursive_mutexboost::recursive_try_mutexboost::recursive_timed_mutex

如果一個執行緒鎖定一個mutex後,而沒有解鎖,就會發生死鎖,這也是最為常見的錯誤了,為此,Boost.Threads專門進行了設計,可不直接對mutex加鎖或者解鎖操作,以使這種錯誤不可能發生(或至少很難發生)。取而代之地,mutex類定義了內嵌的typedef來實現RAII(Resource Acquisition In Initialization,譯註:在初始化時資源獲取)[4]用以對一個mutex進行加鎖或者解鎖,這就是所謂的Scoped Lock模式。要構建一個這種型別的鎖,需要傳遞一個mutex引用,建構函式將鎖定mutex,解構函式將解鎖mutexC++語言規範確保了解構函式總是會被呼叫,所以即使有異常丟擲,mutex也會被正確地解鎖。

這種模式確保了mutex的正確使用。不過必須清楚,儘管Scoped Lock模式保證了mutex被正確解鎖,但它不能保證在有異常丟擲的時候,所有共享資源任然處於有效的狀態,所以,就像進行單執行緒程式設計一樣,必須確保異常不會讓程式處於不一致的狀態。同時,鎖物件不能傳遞給另外一個執行緒,因為他們所維護的狀態不會受到此種用法的保護。

列表2舉例說明了boost::mutex類的一個簡單的用法。其中兩個執行緒被建立,每個迴圈10次,將id和當前迴圈計數輸出到std::coutmain執行緒等待著兩個執行緒結束。std::cout物件是一個共享資源,所以每個執行緒均使用全域性mutex,以確保在同一時刻,只有一個執行緒輸出到它。

#include <boost/thread/thread.hpp>

#include <boost/thread/mutex.hpp>

#include <iostream>

boost::mutex io_mutex;

struct count

{

         count(int id) : id(id) { }

         void operator()()

         {

                   for (int i = 0; i < 10; ++i)

                   {

                            boost::mutex::scoped_lock lock(io_mutex);

                            std::cout << id << ": " << i << std::endl;

                   }

         }

         int id;

};

int main(int argc, char* argv[])

{

         boost::thread thrd1(count(1));

         boost::thread thrd2(count(2));

         thrd1.join();

         thrd2.join();

         return 0;

}

列表2

也許你已經注意到在列表2的程式碼中,需要手工寫一個函式物件,才能向執行緒傳遞資料。儘管程式碼很簡單,但每次都要寫這樣的程式碼也會讓人有單調沉悶之感。有另外一種更容易的解決辦法,Functional庫可以讓你通過將需要傳入的資料繫結到另外一個函式物件的方式,來建立一個新的函式物件。列表3展示了Boost.Bind庫如何不寫函式物件,而簡化列表2中的程式碼。

// This program is identical to listing2.cpp except that it uses

// Boost.Bind to simplify the creation of a thread that takes data.

#include <boost/thread/thread.hpp>

#include <boost/thread/mutex.hpp>

#include <boost/bind.hpp>

#include <iostream>

boost::mutex io_mutex;

void count(int id)

{

         for (int i = 0; i < 10; ++i)

         {

                   boost::mutex::scoped_lock lock(io_mutex);

                   std::cout << id << ": " << i << std::endl;

         }

}

int main(int argc, char* argv[])

{

         boost::thread thrd1(boost::bind(&count, 1));      // 有無&符號均可

         boost::thread thrd2(boost::bind(&count, 2));      // 有無&符號均可

         thrd1.join();

         thrd2.join();

         return 0;

}

列表3

條件變數

有時候僅僅鎖定一個共享資源去使用它還是不夠的。共享資源在被使用之前,有時候它必須處在某種特殊的狀態。例如,一個執行緒有可能試圖從一個棧裡面取資料,如果棧中沒有資料的話,它要等待新的資料的到來。mutex處理這種同步問題就顯得力不從心了。另外一種同步方式,即所謂的條件變數,正好適用於這種情形。

條件變數總是和mutex、共享資源聯合使用。執行緒首先鎖定mutex,然後驗證共享資源是否處於一種可以被安全使用的狀態,如果沒有處在所需要的狀態,那麼執行緒將等待條件變數。這個操作會導致在等待的過程中,mutex被解鎖,從而讓另外一個執行緒可以改變共享資源的狀態。執行緒從等待操作返回時,mutex將肯定是被鎖定的。如果另外一個執行緒改變了共享資源的狀態,它必須通知其他正在等待條件變數的執行緒,從而可以使他們從等待操作中返回。

#include <boost/thread/thread.hpp>

#include <boost/thread/mutex.hpp>

#include <boost/thread/condition.hpp>

#include <iostream>

const int BUF_SIZE = 10;

相關推薦

Boost.thread 同步

參考  http://patmusing.blog.163.com/blog/static/1358349602010183920489/  標準C++執行緒即將來臨,而且將會從Boost Threads發展而來,研究一下由Boost Th

java多執行緒物件、類同步機制

1.在java多執行緒程式設計中物件鎖、類鎖、同步機制synchronized詳解:     物件鎖:在java中每個物件都有一個唯一的鎖,物件鎖用於物件例項方法或者一個物件例項上面的。     類鎖:是用於一個類靜態方法或者class物件的,一個

java多執行緒物件 同步機制

分享一下我老師大神的人工智慧教程吧。零基礎,通俗易懂!風趣幽默!http://www.captainbed.net/ 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

抽象同步佇列AQS——AbstractQueuedSynchronizer

AQS——鎖的底層支援 談到併發,不得不談ReentrantLock;而談到ReentrantLock,不得不談Abstrac

執行緒同步自旋

一 什麼是自旋鎖 自旋鎖(Spinlock)是一種廣泛運用的底層同步機制。自旋鎖是一個互斥裝置,它只有兩個值:“鎖定”和“解鎖

04-drbd的同步模式

51cto cto process -o src text 數據一致性 級別 一致性 df 工作中主要選擇c模式級別,除非工作中的性能大於數據一致性,可以選擇其他級別 2)異步同步模式:04-drbd的同步模式詳解

[數據庫事務與]三: 深入分析事務的隔離級別

不可 ans 提高 重要 不能 標準 insert lec 使用 註明: 本文轉載自http://www.hollischuang.com/archives/943 本文詳細介紹四種事務隔離級別,並通過舉例的方式說明不同的級別能解決什麽樣的讀現象。並且介紹了在關系型數據

[數據庫事務與]一: 徹底理解數據庫事務

存儲 數量 情況 一個數 就是 可能 發生 http 舉例 註明: 本文轉載自http://www.hollischuang.com/archives/898 事務 事務(Transaction),一般是指要做的或所做的事情。在計算機術語中是指訪問並可能更新數據庫中各種

[數據庫事務與]七: 深入理解樂觀與悲觀

ood insert 影響 hiberna memcach begin 策略 goods 其它 註明: 本文轉載自http://www.hollischuang.com/archives/934在數據庫的鎖機制中介紹過,數據庫管理系統(DBMS)中的並發控制的任務是確保在

rsync+inotify實現文件實時同步-步驟

rsync inotify實驗拓撲(centos7下):192.168.80.181 服務器端(主機名www.aa.com)192.168.80.182 客戶端(主機名www.ab.com)1、使用SSH源:安裝rsync,服務端和客戶端同時安裝,只使用客戶端命令就OK了。systemctl stop fir

linux下rsync文件同步配置

寫入文件 sts ddr ORC 文件的 數據鏡像 根據 數據 watermark 介紹 rsync(remote sync)是unix及類unix平臺下的數據鏡像備份軟件,它不像FTP那樣需要全備份,rsync可以根據數據的變化進行差異備份,從而減少數據流量,提高工作效率

c#多線程thread實例

++ {0} 詳解 實現 需要 i++ tostring 返回 主程序 1. Thread線程啟動由於ThreadStart是一個委托,所以可以簡化寫法 static void Main(string[] args) {

【轉】【MySQL】MySQL

https://www.cnblogs.com/luyucheng/p/6297752.html   一、概述 資料庫鎖定機制簡單來說,就是資料庫為了保證資料的一致性,而使各種共享資源在被併發訪問變得有序所設計的一種規則。對於任何一種資料庫來說都需要有相應的鎖定機制,所以MyS

MySQL資料庫的【轉】

當然在我們的資料庫中也有鎖用來控制資源的併發訪問,這也是資料庫和檔案系統的區別之一。 為什麼要懂資料庫鎖? 通常來說對於一般的開發人員,在使用資料庫的時候一般懂點 DQL(select),DML(insert,update,delete)就夠了。 小明是一個剛剛畢業在網際網路公司工作的 Java 開發工

rsync同步命令

一、rsync命令的解釋sync(Synchronize,即“同步”)為UNIX作業系統的標準系統呼叫,功能為將核心檔案系統緩衝區的所有資料(也即預定將通過低階I/O系統呼叫寫入儲存介質的資料)寫入儲存介質(如硬碟)。sync是一個linux同步命令,含義為迫使緩衝塊資料立即寫盤並更新超級塊。在linux系統

goroutine和channel與死

Go語言中有個概念叫做goroutine, 這類似我們熟知的執行緒,但是更輕。 goroutine和執行緒的具體區別在於: 1. OS的執行緒由OS核心排程,每隔幾毫秒,一個硬體時鐘中斷髮到CPU,CPU呼叫一個排程器核心函式。這個函式暫停當前正在執行的執行緒,把他的暫存器資訊儲存到記憶體中

SqlServer資料庫同步方案(包括跨網段)

下載網站:www.SyncNavigator.CN   ---------------------------------------------------------- HKROnline SyncNavigator 8.4.1 非破解版 註冊機 授權啟用教程

logstash-input-jdbc實現mysql 與elasticsearch實時同步深入

引言: elasticsearch 的出現使得我們的儲存、檢索資料更快捷、方便。但很多情況下,我們的需求是:現在的資料儲存在mysql、oracle等關係型傳統資料庫中,如何儘量不改變原有資料庫表結構,將這些資料的insert,update,delete操作結果實時同步到elasticsearch(

MySQL事務與

事務 事務支援ACID特性 A原子性:所有操作要麼都做要麼都不做 C一致性:事務將資料庫從一種狀態變為另一種狀態一致性,保證資料庫完整性約束,例如唯一索引約束等 I隔離性:事務與事務之間是不可見的 D永續性:事務一旦提交那麼事務就是永久性的 ANSI/ISO SQL標準定義了4中

MySQL中(行、表、頁、悲觀、樂觀等)

原文地址:http://blog.csdn.net/mysteryhaohao/article/details/51669741 鎖,在現實生活中是為我們想要隱藏於外界所使用的一種工具。在計算機中,是協調多個程序或執行緒併發訪問某一資源的一種機制。在資料庫當中,除了傳統