簡體   English   中英

具有 AutoResetEvent 的消費者/生產者

[英]Consumer/Producer with AutoResetEvent

我在 C# 中有以下代碼,用於使用 AutoResetEvent 的消費者和生產者,但它們在有多個生產者和一個消費者的情況下不起作用。 問題是消費者不能消費隊列中的所有項目。 當我調試時,我注意到消費者只能刪除一項,然后返回 false 並且無法再刪除。 似乎問題出在 AutoResetEvent 中,但我不知道出了什么問題。

private AutoResetEvent newItemSignal = new AutoResetEvent(false);
private Queue<Task> iQueue = new Queue<Task>();

public void Enqueue(Task task)
{
    lock (((ICollection)iQueue).SyncRoot)
    {
        iQueue.Enqueue(task);
        newItemSignal.Set();
    }
}



public bool Dequeue(out Task task, int timeout)
{
    if (newItemSignal.WaitOne(timeout, false))
    {
        lock (((ICollection)iQueue).SyncRoot)
        {
            task = iQueue.Dequeue();
        }
        return true;
    }
    task = default(Task);
    return false;
}

使用像這樣的 AutoResetEvent 的問題是您可以調用 Set() 兩次或更多次,但 WaitOne() 只調用一次。 在已發出信號的 ARE 上調用 Set() 將始終失敗,該項目卡在隊列中。 一個標准的線程競爭錯誤。 看起來您可以通過清空消費者中的整個隊列來修復它。 不是真正的解決方案,生產者仍然可以領先於消費者,您只是將幾率降低到每月一次不可調試的階段。

ARE 無法做到這一點,它無法計數。 改用 Semaphore/Slim,它以線程安全的方式進行計數。 或者使用 ConcurrentQueue,添加一個類來解決此類編程問題。

通過使用 AutoResetEvent,您將程序設計為一次只有一個消費者可以消費一個項目。

如果你想堅持類似的設計,你可以改用ManualResetEvent,當任何一個消費者線程發現沒有要消費的項目時重置事件,當生產者線程知道至少有一個項目時設置事件要消耗的物品。

您可以在此處找到 Monitor 類的替代設計

如果您使用的是 .NET 4.0 或更高版本,您還可以使用Blocking 集合

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM