一般來說,執行緒同步比較讓人糾結的地方在於它是許多執行緒共用一段**的,而且什麼時候誰用誰不用,也基本是不可控制不可預料的,那麼對於它們可能會同時訪問並更改的資料,就需要加鎖了。加鎖就是將一段**變為臨界區 —— 一段在同一時候只被乙個執行緒進入/執行的**,加鎖的方式一般有兩種,lock關鍵字
c#提供lock關鍵字實現臨界區,msdn裡給出的用法:
object thislock= new object();
lock (thislock)
此方法的難點是如何選擇鎖的物件,比如寫日誌類,如果是靜態物件鎖自身,那麼即使是不衝突的操作,也會互斥,白白浪費了cpu的時間片(像是你所在的a車道可以走了,但非要等到b車道空閒了,你才開始走a車道)
普通的需要例項化的類也要注意,如果是鎖this,那麼一旦這個物件有多個例項,那麼多個例項的操作就變成不互斥了,因為它們鎖住的不是同乙個thislock
,同時也可以在外部宣告乙個object,將引用傳入臨界區,讓臨界區鎖住這個物件,但這種方式比較靈活,但使用起來也需要很小心的維護這個引用。
還有種方法是使用 monitor
system.objectobj = (system.object)x;
system.threading.monitor.enter(obj);
tryfinally
enter和exit 望文生義,就是進入臨界區和離開臨界區,其實和lock使用起來沒什麼區別,只是多了個finally,在這裡你可以多做一些事情,類似於using的自動dispose和尋常的try finally dispose的區別。不過monitor還有一些其他方法,如wait和pulse,可以起到暫停執行緒和通知擁有鎖物件的執行緒的作用,但我不明白的是,為什麼這兩個也是靜態方法。對於它的執行機制,還不太了解。
還有mutex也可以完成同步,但是用法比較複雜,它的特性是可以在程序中同步,所以執行緒同步一般不會用它。
system
.object
system
.marshalbyrefobject
system.threading
.waithandle
system.threading .mutex
也可以合理利用volatile
關鍵字,
(msdn
)volatile
關鍵字指示乙個字段可以由多個同時執行的執行緒修改。
宣告為volatile
的字段不受編譯器優化(假定由單個執行緒訪問)的限制。
這樣可以確保該字段在任何時間呈現的都是最新的值。
volatile
修飾符通常用於由多個執行緒訪問但不使用
lock
語句對訪問進行序
列化的字段。
volatile 關鍵字可應用於以下型別的字段:
可變關鍵字僅可應用於類或結構字段。不能將區域性變數宣告為 volatile。
執行緒同步易出錯的地方是,全域性變數和靜態變數,這個必須非常小心。
前面也提到了,執行緒是共享資源的,所以每乙個執行緒都是訪問的同乙個全域性變數和靜態變數(區域性變數無此隱患)。
乙個很簡單的示例,
int 全域性變數 i
13else
4i++ ;
} 這段**在多個執行緒裡面被併發執行,檢視輸出,會發現很多錯誤,因為1執行完畢,進入2或3,但還未執行,這時其他執行緒可能執行了4,所以i被++了。
linux 多執行緒通訊(三)執行緒的同步
同步 當多個執行緒共享相同的記憶體時,需要每乙個執行緒看到相同的試圖,當乙個執行緒修改變數時,其他執行緒也可以讀取或修改這個變數,就需要執行緒的同步,確保他們不會訪問到無效的變數。互斥量 在變數修改時間多於以乙個儲存器訪問週期的處理器結構中,當儲存器的讀和寫這兩個週期交叉時,這種潛在的不一致性就會出...
OpenMP(三) 執行緒同步
1.引言 在openmp中,執行緒同步機制包括互斥鎖同步機制和事件同步機制。2.互斥鎖同步 互斥鎖同步的概念類似於windows中的臨界區 criticalsection 以及windows和linux中的mutex以及vxworks中的semtake和semgive 初始化時訊號量為滿 即對某一塊...
執行緒實用解析 (三)執行緒的同步
上一節主要講了建立呼叫有參 多參 函式的執行緒和執行緒池的一些內容,這一節主要講執行緒的同步。多執行緒的出現解決了吞吐量和響應速度的問題,但同時也帶來了資源共享問題,如死鎖和資源爭用。在為單個資源分配多個執行緒可能會導致同步問題。何為執行緒同步呢?所謂同步,是指多個執行緒之間存在先後執行順序的關聯關...