[英]Waking a thread up from sleep when a collection is modified
我有一個在隊列上工作的方法。 在消耗隊列中的第一個對象之后,它進入休眠狀態一段預定義的時間(例如10秒)。 如果隊列被第3或第4秒的任何其他線程修改,有沒有辦法喚醒該線程?
您應該使用專為此目的而設計的集合。 一個例子是BlockingCollection
,它允許你從集合中獲取一個項目,如果沒有要采取的項目,該方法將阻塞,直到有一個項目給你。 它也是一個專門設計用於從多個線程進行操作的集合,可以減輕您的同步負擔。
請注意,可以初始化BlockingCollection
以便使用不同類型的集合進行備份。 默認情況下,它將使用ConcurrentQueue
,但是如果您不想要隊列語義,則可以使用System.Collections.Concurrent
命名空間中的其他集合(但您似乎可以這樣做)。 如果你真的需要一些獨特的東西,你也可以實現你自己的集合實現IProducerConsumerCollection<T>
。
在任何情況下,我都建議不要使用Thread.Sleep()
因為它完全阻止了線程。
使用AutoResetEvent
或ManualResetEvent
來同步兩個或多個線程要好得多:
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.