2011-12-02 97 views
1

是否有可能(以有意義的方式)?如何繼承WaitHandle?

例如,假設我想實現一個可等待隊列如下:

public class WaitableQueue : WaitHandle { 
    public WaitableQueue() { 
     q = new Queue(); 
    } 

    public void Enqueue(Object Arg) { 
     lock(this) { 
     q.Enqueue(Arg); 
     // set the waithandle here (how?) 
     } 
    } 

    public Type Dequeue() { 
     lock(this) { 
     if(q.Count == 1) 
     // reset the waithandle here (how?) 
     return q.Dequeue(); 
     } 
    } 

    Queue q; 
    } 
+0

如果可能的話,你是如何使用它的? –

+0

[C#中的隊列和等待句柄]的可能重複(http://stackoverflow.com/questions/2741042/queues-and-wait-handles-in-c-sharp) –

+0

不可以。我給出的例子恰好與關於隊列的實際問題相吻合。 – schwrz

回答

6

重要的是要記住,您必須設置SafeWaitHandle屬性。

從MSDN:

當您從WaitHandle中派生,使用SafeWaitHandle屬性 儲存您的原生手柄操作系統句柄。除非使用其他 非託管資源,否則不需要 覆蓋受保護的Dispose方法。

這裏是我將如何做到這一點。

public class QueueWaitHandle<T> : WaitHandle 
{ 
    private Queue<T> queue = new Queue<T>(); 
    private ManualResetEvent signal = new ManualResetEvent(false); 

    public QueueWaitHandle() 
    { 
     base.SafeWaitHandle = signal.SafeWaitHandle; 
    } 

    public void Enqueue(T item) 
    { 
     lock (queue) 
     { 
      queue.Enqueue(item); 
      signal.Set(); 
     } 
    } 

    public T Dequeue() 
    { 
     lock (queue) 
     { 
      T item = queue.Dequeue(); 
      if (queue.Count == 0) 
      { 
       signal.Reset(); 
      } 
      return item; 
     } 
    } 
} 

當完成這樣Enqueue行爲像Set方法和Dequeue行爲像Reset方法。所以基本上這就像一個計數事件,其中非零信號發出,零信號無信號。在這種情況下,隊列正在進行計數,而且恰好也會保存數據。

我知道你一般都在詢問子類化WaitHandle,但是這個特定的數據結構不僅僅是一個練習。它在某些情況下可能很有用。但是,我不會將其稱爲等待隊列,因爲這意味着(至少對我而言),當隊列爲空時,Dequeue操作將被阻止。顯然這不是在這個特定的實現中會發生什麼。

+0

您始終可以擁有Dequeue(bool Blocking),但在任何情況下,這都是我一直在尋找的解決方案。我希望能夠保護Set和Reset或者受保護的ctor有一個參數,就像在WaitHandle(SafeWaitHandle Handle)中一樣。我找不到這些,那就是把我扔掉的東西(可惜我也錯過了你引用的MSDN位)。我的問題確實是一般性的,但它確實來自現實生活場景,您的解決方案將得到很好的利用。謝謝! – schwrz

0

我認爲這不是一個好的使用繼承。你的對象的一個隊列,使用一個等待句柄來提供線程安全,所以你不應該從WaitHandle派生。

+0

我並不是專門尋求實現一個等待隊列。這只是一個例子。我在問WaitHandle是否可以用有意義的方式派生(參見我的原文) – schwrz

+1

它是一個抽象基類,所以它是由.NET框架中的所有具體同步類以有意義的方式派生的(Mutex ,信號量等)。我相信你可以使用它來開發.NET以外不支持的另一種類型的同步原語。 – jlew

+0

你會怎麼做呢?在我看來,無法使用.NET基元來完成,因爲您無法控制繼承的句柄。 – schwrz

1

我想創建它彙集雙方隊列,WaitHandle的一類,因此:

public class WaitableQueue<T> 
{ 
    private Queue<T> _queue; 
    private WaitHandle _waitHandle; 

    public WaitableQueue() 
    { 
     _queue = new Queue<T>(); 
     _waitHandle = new WaitHandle(); 
    } 

    public void Enqueue(T Arg) { 
     lock(this) { 
     _queue.Enqueue(Arg); 
     _waitHandle.Set(); 
     } 
    } 
    ... 
} 
+0

當然,但後來我無法:WaitHandle.WaitAny(q1,q2)... – schwrz

+1

也許_waitHandle應該作爲只讀公共屬性公開並且/或者應該有構造函數重載,它接受WaitHandle作爲參數。這樣,您可以使用這個WaitableQueue類,如果您需要執行WaitHandle.WaitAny(q1,q1,...),那麼您仍然可以這樣做,因爲您可以訪問隊列正在使用的WaitHandle。 –

+1

如果您將_waitHandle作爲公共'get'屬性 –

3

的的EventWaitHandle類有設置和重置的方法,所以你可以從替代的WaitHandle的繼承。

但是,我想說,對於提供的示例,我認爲這不是一個好的實現,因爲SafeWaitableQueue類現在有兩個不同的角色:一個隊列和一個等待句柄。

但是,如果你有其他想法,你需要實現自己的等待句柄,我會建議嘗試從EventWaitHandle繼承。

這不是一個好的解決方案,因爲Set和Reset方法是公開公開的,這意味着您的SafeWaitableQueue類的消費者也可以調用Set和Reset,可能導致一些決定性的安全行爲。

+0

我認爲EventWaitHandle會像AutoResetEvent和ManualResetEvent一樣被密封。正如您正確指出的那樣,曝光問題是一個問題。 – schwrz