簡體   English   中英

修改集合時從睡眠狀態喚醒線程

[英]Waking a thread up from sleep when a collection is modified

我有一個在隊列上工作的方法。 在消耗隊列中的第一個對象之后,它進入休眠狀態一段預定義的時間(例如10秒)。 如果隊列被第3或第4秒的任何其他線程修改,有沒有辦法喚醒該線程?

您應該使用專為此目的而設計的集合。 一個例子是BlockingCollection ,它允許你從集合中獲取一個項目,如果沒有要采取的項目,該方法將阻塞,直到有一個項目給你。 它也是一個專門設計用於從多個線程進行操作的集合,可以減輕您的同步負擔。

請注意,可以初始化BlockingCollection以便使用不同類型的集合進行備份。 默認情況下,它將使用ConcurrentQueue ,但是如果您不想要隊列語義,則可以使用System.Collections.Concurrent命名空間中的其他集合(但您似乎可以這樣做)。 如果你真的需要一些獨特的東西,你也可以實現你自己的集合實現IProducerConsumerCollection<T>

而不是Thread.Sleep

您可以使用Monitor.Wait超時,如果需要從任何線程,您可以使用Monitor.Pulse將其喚醒。

這里真的很好的例子/解釋

在任何情況下,我都建議不要使用Thread.Sleep()因為它完全阻止了線程。

使用AutoResetEventManualResetEvent來同步兩個或多個線程要好得多:

https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx

使用Blocking Collection, Servy有正確的答案。

只是進一步添加:當“工作”項在隊列中可用並在該線程上異步處理它時,它會創建一個新線程池池線程。

您可以在生產者/消費者隊列中使用一個:

例如:

/// <summary>
/// Producer/consumer queue. Used when a task needs executing, it’s enqueued to ensure order, 
/// allowing the caller to get on with other things. The number of consumers can be defined, 
/// each running on a thread pool task thread. 
/// Adapted from: http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT
/// </summary>
public class ProducerConsumerQueue : IDisposable
{
    private BlockingCollection<Action> _taskQ = new BlockingCollection<Action>();

    public ProducerConsumerQueue(int workerCount)
    {
        // Create and start a separate Task for each consumer:
        for (int i = 0; i < workerCount; i++)
        {
            Task.Factory.StartNew(Consume);
        }
    }

    public void Dispose() 
    { 
        _taskQ.CompleteAdding(); 
    }

    public void EnqueueTask(Action action) 
    { 
        _taskQ.Add(action); 
    }

    private void Consume()
    {
        // This sequence that we’re enumerating will block when no elements
        // are available and will end when CompleteAdding is called.
        // Note: This removes AND returns items from the collection.
        foreach (Action action in _taskQ.GetConsumingEnumerable())
        {
            // Perform task.
            action();
        }
    }
}

謝謝大家的建議。 我終於根據這個要求確定了AutoResetEvent。 在使用隊列中的第一個對象之后,我沒有將主線程置於Sleep狀態,而是從主線程中生成了一個新線程,我稱之為sleep。 主線程只會等待。 一旦新線程被喚醒,它將使用Set向主線程發出信號,主線程將恢復。 這是一部分。

第二部分 - 如果任何其他線程修改隊列,即使該線程將在同一EventWaitHandle上調用Set,從而再次使主線程恢復。

這可能不是最佳解決方案,但比其他方法更簡單。

我會把線程進入一個while迭代,然后睡眠時間減少到像200毫秒。

但是在每次迭代中,我都會檢查隊列是否被修改。 這樣,當隊列被修改時,線程始終處於睡眠模式並且會被喚醒。

如果要停止線程,只需將while條件設置為false

暫無
暫無

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

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