2010-12-08 79 views
11

我試圖使用CountdownEvent只允許線程在事件的計數爲零時繼續,但是我希望初始計數爲零。實際上,我想返回到零行爲,從而當計數爲零並且線程被設置爲等待大於零時等待該事件。返回零倒數事件

我可以使用0初始計數來初始化倒計時事件,但是當我嘗試添加計數時,我會得到InvalidOperationException「CountdownEvent_Increment_AlreadyZero」。

是否有其他類別或其他方式可以使用Countdown事件以避免此限制?

+0

你有沒有解決過這個問題?你是怎麼做到的? – HAL9000 2011-04-15 20:31:42

回答

0

如何信號燈:http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

編輯:下面的帖子討論爲什麼你描述是不推薦,什麼也提出了一種解決方法:http://social.msdn.microsoft.com/Forums/en/parallelextensions/thread/aa49f92c-01a8-4901-9846-91bc1587f3ae

+0

你能舉出一個如何使用它們的例子嗎?我想到了他們,但無法避免需要知道最大數量。 – chillitom 2010-12-08 13:51:23

+0

你可以發佈你的非工作代碼,這樣我可以更好地理解你想要實現的目標嗎? – SpeksETC 2010-12-08 18:32:10

1

所以在本質上,你需要一個「ON/OFF開關」,不是可以用任意倒計數器設置的同步對象。 CountdownEvent不適合這種情況。

爲什麼不使用Semaphore,初始值爲1?

+0

不完全,重要的是我有這種計數行爲。實際上,我正在執行的操作將會創建未知數量的子操作(不是任務或線程),當每次操作開始時我會收到一個信號,並且每次操作結束時都會收到一個信號。我不想繼續下去,直到所有的子操作完成。 (fyi,我在本地dll上寫了一個相當棘手的約束,因此這是不尋常的要求) – chillitom 2010-12-08 13:56:15

1

如果您可以將.NET 4.0或Reactive Extensions用於.NET 3.5(它具有.NET 4 TPL功能的反向鏈接),那麼可以查看Barrier類。它允許您協調多個並行任務,以使它們不會繼續,直到障礙中的所有參與者發出信號表示其到達爲止。它也應該滿足您的要求,讓參與者在處理過程中出現和消失。

4

您寫道:

我執行,這將創建一個未知號碼的孩子操作(沒有任務或線程)

那麼,什麼是他們的工作?你應該做這樣的事情:

 
CountdownEvent ev; 
public void foo() { 
    ev = new CountdownEvent(1); 
    foreach (<task in tasks_to_start>) { 
     ev.AddCount(); 
     // enter code here which starts your task 
    } 
    ev.Signal(); 
    ev.Wait(); 
} 

public static void youtTask(CountdownEvent ev) { 
    // some work 
    // ... 
    // after all is done 
    ev.Signal(); 
} 
0

您可以使用一個隊列對象,以「工作」加入到並再次冒了出來。

只有當隊列爲空時,你才能繼續前進。

但是,我們需要細節在這裏...

1

這會爲你工作嗎? http://msdn.microsoft.com/en-us/library/dd384749.aspx

編輯
對不起,這是模糊的。使用SOReader的答案,如果每個家長都有一個倒計時事件,從1開始 - 然後在孩子中使用TryAddCount遞增,然後將父母遞減回1,然後在孩子完成時從父母遞減到1,最後遞減計數父線程的父代。因此,樹狀系列的倒數事件。

我沒有多線程的經驗,但乍一看這就是我會嘗試。

1

你的問題似乎是一個常見的樹行走分叉技術。每次你都要遞歸時,你會發起另一個併發操作(將它排入一個線程池等)。但是你需要等待所有子支路結束。只需爲每次啓動的子操作添加1到倒數事件,並在每個子操作結束時發出信號。只要您安排算法,只要它爲每個子操作添加算法,它就不會發出信號,這是安全的。

我應該補充說,你不要需要知道計數前面,只需使它在根1,並且每次你分叉到一個孩子,加1,然後在每個一個,它會動態處理任何樹,沒有前期成本。

CountdownEvent有一個方法添加它可以讓您增加飛行中的計數。

這有道理嗎?我可能會遠離你想要完成的事情。但是,如果您確實需要按照您指定的方式運行的CountdownEvent,則可以很容易地將一些互鎖操作封裝在類中以執行您所說的操作。

但是,CountdownEvent的構建是羽毛重量,如果沒有人在信號發出之前等待,它幾乎是免費的。在昂貴的情況下,它是最優的,無論有多少任務(等),它只會讓一個內核轉換到信號,一個等待,最壞的情況。

爲了實現你的建議,需要圍繞信號和事件重置進行同步。倒計時事件依賴於一個簡單的原則,只有在信號調用中從非零到零的轉換纔可能發出事件信號。沒有競爭,因爲多個線程不可能同時更改值(它是互鎖的),所以只有一個線程可以嘗試發信號通知事件對象(喚醒另一個等待線程)。完善。但是,如果您有多個線程設置並將其重置,則需要同步設置和重置,因爲計數可能會抖動幾次,並且多個線程都會同時嘗試設置或重置事件。 (設置,重置和等待事件都很昂貴,因爲它們都必須進行內核轉換並導致上下文切換)。除非您保護設置/重置轉換,否則它將無法工作。如果他們將此添加到CountdownEvent中,它將不再是幾乎最佳的,它將顯着更昂貴。