C 中幾種同步的方法

2021-12-29 16:30:29 字數 3212 閱讀 6437

在網上有很多關於執行緒同步的文章,其實執行緒同步有好幾種方法,下面簡單的做一下歸納。

一、volatile關鍵字

volatile是最簡單的一種同步方法,當然簡單是要付出代價的。它只能在變數一級做同步,volatile的含義就是告訴處理器,不要將我放入工作記憶體,請直接在主存操作我。(【**www.bitscn.com 】)因此,當多執行緒同時訪問該變數時,都將直接操作主存,從本質上做到了變數共享。

能夠被標識為volatile的必須是以下幾種型別:(摘自msdn)

# any reference type.

# any pointer type (in an unsafe context).

# the types sbyte, byte, short, ushort, int, uint, char, float, bool.

# an enum type with an enum base type of byte, sbyte, short, ushort, int, or uint.

如:code

public class a

set }}

但volatile並不能實現真正的同步,因為它的操作級別只停留在變數級別,而不是原子級別。如果是在單處理器系統中,是沒有任何問題的,變數在主存中沒有機會被其他人修改,因為只有乙個處理器,這就叫作processor self-consistency。但在多處理器系統中,可能就會有問題。每個處理器都有自己的data cach,而且被更新的資料也不一定會立即寫回到主存。所以可能會造成不同步,但這種情況很難發生,因為cach的讀寫速度相當快,flush的頻率也相當高,只有在壓力測試的時候才有可能發生,而且機率非常非常小。

二、lock關鍵字

lock是一種比較好用的簡單的執行緒同步方式,它是通過為給定物件獲取互斥鎖來實現同步的。它可以保證當乙個執行緒在關鍵**段的時候,另乙個執行緒不會進來,它只能等待,等到那個執行緒物件被釋放,也就是說執行緒出了臨界區。用法:

code

public void function()

}lock的引數必須是基於引用型別的物件,不要是基本型別像 bool,int什麼的,這樣根本不能同步,原因是lock的引數要求是物件,如果傳入int,勢必要發生裝箱操作,這樣每次lock的都將是乙個新的不同的物件。最好避免使用public型別或不受程式控制的物件例項,因為這樣很可能導致死鎖。特別是不要使用字串作為lock的引數,因為字串被 clr「暫留」,就是說整個應用程式中給定的字串都只有乙個例項,因此更容易造成死鎖現象。建議使用不被「暫留」的私有或受保護成員作為引數。其實某些類已經提供了專門用於被鎖的成員,比如array型別提供syncroot,許多其它集合型別也都提供了syncroot。

所以,使用lock應該注意以下幾點:

1、如果乙個類的例項是public的,最好不要lock(this)。因為使用你的類的人也許不知道你用了lock,如果他new了乙個例項,並且對這個例項上鎖,就很容易造成死鎖。

2、如果mytype是public的,不要lock(typeof(mytype))

3、永遠也不要lock乙個字串

三、system.threading.interlocked

對於整數資料型別的簡單操作,可以用 interlocked 類的成員來實現執行緒同步,存在於system.threading命名空間。interlocked類有以下方法:increment , decrement , exchange 和compareexchange 。使用increment 和decrement 可以保證對乙個整數的加減為乙個原子操作。exchange 方法自動交換指定變數的值。compareexchange 方法組合了兩個操作:比較兩個值以及根據比較的結果將第三個值儲存在其中乙個變數中。比較和交換操作也是按原子操作執行的。如:

code

int i = 0 ;

system.threading.interlocked.increment( ref i);

console.writeline(i);

system.threading.interlocked.decrement( ref i);

console.writeline(i);

system.threading.interlocked.exchange( ref i, 100 );

console.writeline(i);

system.threading.interlocked.compareexchange( ref i, 10 , 100 );

output:

四、monitor

monitor類提供了與lock類似的功能,不過與lock不同的是,它能更好的控制同步塊,當呼叫了monitor的enter(object o)方法時,會獲取o的獨占權,直到呼叫exit(object o)方法時,才會釋放對o的獨占權,可以多次呼叫enter(object o)方法,只需要呼叫同樣次數的exit(object o)方法即可,monitor類同時提供了tryenter(object o,[int])的乙個過載方法,該方法嘗試獲取o物件的獨占權,當獲取獨占權失敗時,將返回false。

但使用 lock 通常比直接使用 monitor 更可取,一方面是因為 lock 更簡潔,另一方面是因為 lock 確保了即使受保護的**引發異常,也可以釋放基礎監視器。這是通過 finally 中呼叫exit來實現的。事實上,lock 就是用 monitor 類來實現的。下面兩段**是等效的:

code

lock (x)

等效於object obj = ( object )x;

system.threading.monitor.enter(obj);

tryfinally

關於用法,請參考下面的**:

code

private static object m_monitorobject = new object ();

[stathread]

static void main( string args)

static void do()

tryfinally

}當執行緒1獲取了m_monitorobject物件獨占權時,執行緒2嘗試呼叫tryenter(m_monitorobject),此時會由於無法獲取獨占權而返回false,輸出資訊如下:

另外,monitor 還提供了三個靜態方法 monitor.pulse(object o),monitor.pulseall(object o)和monitor.wait(object o ) ,用來實現一種喚醒機制的同步。關於這三個方法的用法,可以參考msdn,這裡就不詳述了。

五、mutex

C 執行緒同步的幾種方法

幾種方法 我們在程式設計的時候,有時會使用多執行緒來解決問題,比如你的程式需要在後台處理一大堆資料,但還要使使用者介面處於可操作狀態 或者你的程式需要訪問一些外部資源如資料庫或網路檔案等。這些情況你都可以建立乙個子執行緒去處理,然而,多執行緒不可避免地會帶來乙個問題,就是執行緒同步的問題。如果這個問...

C 執行緒同步的幾種方法

我們在程式設計的時候,有時會使用多執行緒來解決問題,比如你的程式需要在後台處理一大堆資料,但還要使使用者介面處於可操作狀態 或者你的程式需要訪問一些外部資源如資料庫或網路檔案等。這些情況你都可以建立乙個子執行緒去處理,然而,多執行緒不可避免地會帶來乙個問題,就是執行緒同步的問題。如果這個問題處理不好...

C 執行緒同步的幾種方法

我們在程式設計的時候,有時會使用多執行緒來解決問題,比如你的程式需要在後台處理一大堆資料,但還要使使用者介面處於可操作狀態 或者你的程式需要訪問一些外部資源如資料庫或網路檔案等。這些情況你都可以建立乙個子執行緒去處理,然而,多執行緒不可避免地會帶來乙個問題,就是執行緒同步的問題。如果這個問題處理不好...