1. 程式人生 > >執行緒基礎之JAVA和C++0x的特性

執行緒基礎之JAVA和C++0x的特性

譯文連線   譯文地址  譯者:衣著時   校對:丁一    (有興趣參與試譯或校對的同學,請加入併發網試譯者QQ群:369468545)

JAVA特性

JAVA執行緒通常是一個帶有run()方法的java.lang.Thread的子類,然後呼叫這個子類物件的start()方法。我們之前定義過,資料競爭是因為兩個執行緒同時訪問記憶體單元,在JAVA中,記憶體單元是一個物件欄位或陣列元素。

由於JAVA旨在支援執行不受信任程式碼作為受信任的應用程式的一部分,必須限制不受信任程式碼的資料爭用造成的破壞。因此不允許資料爭用的任意行為,所以,JAVA語言規範包含了一個複雜的規則集,用來定義執行緒間的共享物件的行為,包括資料爭用的行為,這些規則的影響甚至專家都覺得驚訝。然而這些規則保證了免除資料爭用的程式的連續一致,對於程式來講是個更加容易的模型。

如上所述JAVA的資料爭用定義的可替換的定義是,併發衝突操作必須被阻止同時出現通過執行相同的執行緒,或者引入強制實施執行緒間的順序的同步變數。如果採用了這些機制,就可以說一個記憶體操作發生在另一個記憶體操作之前。因此不會發生交叉儲存。這基本相當於我們的定義。

在幾乎所有情況下,Java程式應該避免資料競爭,和依賴順序一致性。事實上附加的保障資料競爭問題只有三種情況:

1.對於編譯器,必須保護它們。

2.對於尤其安全的敏感的程式碼,作者需要限制不受信任的“沙箱”程式碼引起的破壞。

3.對於極其效能敏感程式碼的富有經驗的作者來講,使用同步變數的格外代價太高。儘管這樣的程式碼存在於java.util.concurrent類庫裡,我們還是期望比較少的程式設計師寫這樣的程式碼。

JAVA提供了不同尋常方式的鎖:每個JAVA物件都可以作為一個鎖。即邏輯上有個關聯鎖,而不是提供一個顯式的lock()和unlock()函式。JAVA提供了同步塊來獲得和釋放鎖。在指定的程式碼塊被執行期間一直保持住鎖。

synchronized (object_used_as_lock) {
   <i>code to be executed with lock held</i>
 }

儘管最近JAVA版本提供了顯式鎖操作(java.util.concurent.locks),同步鎖有實質性的好處,鎖可以沿著程式碼塊的方向釋放,其中包括異常被丟擲,從而消除錯誤的常見來源。

正如我們上面提及的,同步變數或者更正確的物件欄位,通常用volatile關鍵字宣告。由於不是一個單獨的型別,可能有些令人驚訝,結果是:

陣列元素不能同步,因為沒有辦法吧陣列元素宣告為volatile。

正如我們前面暗示的,volatile僅僅影響個別的記憶體儲存,如果i被宣告為volatile int i,那麼++i包含兩個單獨的不可分割的記憶體訪問,即增量作為一個不可分割的整體。

Java.util.concurrent.atomic包提供了一些原子型別規避這兩種結果。

Java.util.concurrent提供了許多其他的措施支援多執行緒,包括豐富的類庫用來同步或執行緒間的互動。

一些C++0x 特徵

約定成俗,我們要用術語c++0x指下一個c++標準,儘管我們並不期望它被正式作為一個ISO標準直到2010或2011年。一個委員會起草的標準目前是可用的,並且我們期望許多供應商支援早於2011年的部分,在這我們所有的解釋明確地適應2008委員會草案。

和當前(2003)C++標準不同,C++0X明確的支援執行緒,執行緒通過std::thread類的例項建立,呼叫建構函式或者執行可呼叫的物件。

由於C++沒有被設計來提供保護不受信任的程式碼的,它無法保證資料爭用,允許資料爭用的任意程式產生”未定義行為”。

資料爭用比較少的時候,提供的一些低層次的類庫措施不能用來提供連續一致性。正像JAVA,這顯而易見不是官方語言描述,在這種情況下,不使用資料爭用而用低層次類庫措施的語言描述更為複雜。

可以通過構造互斥獲得鎖,典型的是std::mutex,然後通過它獲得建構函式std::lock_quard物件,確保在lock_quard解構函式釋放鎖,正如JAVA中被釋放,即使是丟擲異常。因此看起來像典型的程式碼來獲得一個鎖。

#include <mutex>
std::mutex mtx; // The lock; shared by multiple threads

{std::lock_guard _(mtx);
  ++c;
}

在c++0x中,整形同步變數i可能被宣告為atomic<int> i;

同步變數與普通變數不同有個不同的型別,因此可以提供成員函式的不同實現,如果i像以上一樣被宣告,併發訪問確保了正如以前一樣的連續一致的行為,但是也確保了一個不可分割的操作,++i自動增加。

(C++裡也有Volatile,由於歷史原因,這意味著別的。)

目前看來,c++0x模型將在其他環境中,目前跡象表明,下一個C標準將遵循一種方法類似c++0x。OpenMP似乎也正走向一個類似解決方案。