[英]thread safe processing of a queue
我將任務從UI線程放入隊列中,以便可以在另一個線程中對其進行處理。 如果無事可做,則線程應等待AutoResetEvent
顯然,所有這些都應該是線程安全的。
我正在將任務從UI線程放入隊列中,如下所示:
lock (_syncObject)
{
_queue.Enqueue(new FakeTask());
}
_autoResetEvent.Set();
到目前為止,這是我的處理線程循環的樣子:
while (true)
{
FakeTask task = null;
lock (_syncObject)
{
if (_queue.Count > 0)
{
task = _queue.Dequeue();
}
}
if (task != null)
{
task.Run();
Thread.Sleep(1000); //just here for testing purposes
}
if (_queue.Count == 0)
{
_autoResetEvent.WaitOne();
}
}
我擔心我檢查隊列中是否還有其他內容的最后一部分不是線程安全的,並且想知道我如何做到這一點。 謝謝!
在簡單的情況下 ,請嘗試使用為實現Producer / Consumer模式 而專門設計的 BlockingCollection :
private async Task Process() {
using (BlockingCollection<FakeTask> _queue = new BlockingCollection<FakeTask>()) {
Task producer = Task.Run(() => {
while (!completed) {
//TODO: put relevant code here
_queue.Add(new FakeTask());
}
_queue.CompleteAdding();
});
Task consumer = Task.Run(() => {
foreach (FakeTask task in _queue.GetConsumingEnumerable()) {
//TODO: process task - put relevant code here
}
});
await Task.WhenAll(producer, consumer).ConfigureAwait(false);
}
}
編輯:如果producer
是UI線程本身:
private async Task Process() {
using (BlockingCollection<FakeTask> _queue = new BlockingCollection<FakeTask>()) {
Task consumer = Task.Run(() => {
foreach (FakeTask task in _queue.GetConsumingEnumerable()) {
//TODO: process task - put relevant code here
}
});
// If we produce in UI we don't want any separate Task
while (!completed) {
//TODO: put relevant code here
_queue.Add(new FakeTask());
}
_queue.CompleteAdding();
await consumer.ConfigureAwait(false);
}
}
如果網格糾纏 (例如,生產者#1,#2為消費者#1,#2,#3生成任務,依次為……創建任務),請嘗試使用DataFlow
僅僅創建一個線程以使它基本上可以將所有時間都花在無所事事的等待工作上是沒有用的。
您需要做的就是圍繞UI任務要完成的后台工作調度使用異步鎖定機制。 SemaphoreSlim
提供了這樣一種異步同步機制。
await sempahoreSlim.WaitAsync();
try
{
await Task.Run(() => DoWork());
}
finally
{
sempahoreSlim.Release();
}
它不僅減少了很多代碼,而且具有更簡單的代碼來更准確地反映應用程序的業務邏輯是什么,而且您消耗的系統資源也大大減少了。
當然,如果不同的后台操作可以安全地並行運行,那么只需使用線程池,而不是您自己的消息循環,代碼就會變得更加簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.