在并行計算中,不可避免的會碰到多個任務共享變量,執行個體,集合。雖然task自帶了兩個方法:task.continuewith()和task.factory
.continuewhenall()來實作任務串行化,但是這些簡單的方法遠遠不能滿足我們實際的開發需要,從.net 4.0開始,類庫給我們提供了很多
的類來幫助我們簡化并行計算中複雜的資料同步問題。
大體上分為二種:
① 并發集合類: 這個在先前的文章中也用到了,他們的出現不再讓我們過多的關注同步細節。
② 輕量級同步機制: 相對于老版本中那些所謂的重量級同步機制而言,新的機制更加節省cpu的額外開銷。
關于并發集合類沒什麼好講的,如果大家熟悉非線程安全的集合,那麼這些并發的集合對你來說小菜一碟,這一篇和下一篇我們仔細來玩玩這
些輕量級的同步機制。
一:barrier(屏障同步)
1:基本概念
msdn對它的解釋是:使多個任務能夠采用并行方式依據某種算法在多個階段中協同工作。乍一看有點不懂,沒關系,我們采取提幹法。
”多個任務“,”多個階段”,“協同”,仔細想想知道了,下一階段的執行必須等待上一個階段中多task全部執行完,那麼我們實際中有這樣
的需求嗎?當然有的,比如我們資料庫中有100w條資料需要導入excel,為了在資料庫中加速load,我們需要開多個任務去跑,比如這
裡的4個task,要想load産品表,必須等4個task都跑完使用者表才行,那麼你有什麼辦法可以讓task為了你兩肋插刀呢?它就是barrier。

好,我們知道barrier叫做屏障,就像下圖中的“紅色線”,如果我們的屏障設為4個task就認為已經滿了的話,那麼執行中先到的task必須等待
後到的task,通知方式也就是barrier.signalandwait(),屏障中線程設定操作為new barrier(4,(i)=>{})。
啰嗦了半天,還是上下代碼說話:
2:死鎖問題
先前的例子我們也知道,屏障必須等待4個task通過signalandwait()來告知自己已經到達,當4個task全部達到後,我們可以通過
barrier.participantsremaining來擷取task到達狀态,那麼如果有一個task久久不能到達那會是怎樣的情景呢?好,我舉個例子。
我們發現程式在加載user表的時候卡住了,出現了類似死循環,這句spinwait.spinuntil(() => barrier.participantsremaining == 0)中
的participantsremaining==0 永遠也不能成立,導緻task0永遠都不能退出,然而barrier還在一直等待task0調用signalandwait來結束屏障。
結果就是造成了互相等待的尴尬局面,我們下個斷點看看情況。
3:逾時機制
當我們coding的時候遇到了這種問題還是很糾結的,是以我們必須引入一種“逾時機制”,如果在指定的時候内所有的參與者(task)都
沒有到達屏障的話,我們就需要取消這些參與者的後續執行,幸好signalandwait給我們提供了逾時的重載,為了能夠取消後續執行,我們
還要采用cancellationtoken機制。
二:spinlock(自旋鎖)
我們初識多線程或者多任務時,第一個想到的同步方法就是使用lock或者monitor,然而在4.0 之後給我們提供了另一把武器spinlock,
如果你的任務持有鎖的時間非常短,具體短到什麼時候msdn也沒有給我們具體的答案,但是有一點值得确定的時,如果持有鎖的時候比較
短,那麼它比那些重量級别的monitor具有更小的性能開銷,它的用法跟monitor很相似,下面舉個例子,add2方法采用自旋鎖。