簡體   English   中英

具有事件驅動工作且沒有關閉的C#工作線程

[英]C# worker thread with event driven work and no shut down

這是我想做的事情:

  1. 在主線程(控制UI)中創建一個工作線程。
  2. 工作線程一直運行,直到被主線程關閉(僅在整個應用程序關閉時才會發生)。
  3. 主線程偵聽keyup,但將事件發送到工作線程以異步處理keyup(以避免阻塞UI)。
  4. 處理完按鍵后,工作線程將更新UI。

到目前為止,每當有一個keyup時,我就一直在創建一個新線程,但是這種方式似乎有太多開銷。

據我所知,我應該使用BackgroundWorker類,但是我所看到的示例似乎是在啟動后台工作程序,在主線程中繼續非阻塞UI,並在完成后從BackgroundWorker中更新UI-即和我已經在做的一樣。

在沒有工作要做的情況下,如何使工作線程保持運行和睡眠?

盡管Zaches的答案是完全有效的(並且我使用了一段時間),但我偶然發現了我認為使用Dispatcher一種更優雅的解決方案:

創建工作線程:

Dispatcher _workerDispatcher;
Thread _workerThread = new Thread(new ThreadStart(() =>
{
    _workerDispatcher = Dispatcher.CurrentDispatcher; // Required to create the dispatcher
    Dispatcher.Run(); // Keeps thread alive and creates a queue for work
});
_workerThread.Start();

將工作放入輔助線程(從主線程或其他線程):

// Synchronous work
_workerDispatcher.Invoke(() =>
{
    // Do stuff
});

// Asynchronous work (makes most sense for background work)
_workerDispatcher.BeginInvoke(() =>
{
    // Do stuff
});

關閉工作線程:

_workerDispatcher.InvokeShutdown();
_workerThread.Join(); // Wait for thread to shut down

我正在使用new Thread()因為我需要設置單元狀態,但是您也可以使用使用Task.Run()Task.Factory.StartNew()創建的任務。

我不是100%肯定有必要調用thread.Join() ,但我想確定線程已關閉。 如果您使用的是Task調用task.Wait()

獲得另一種方式Dispatcher是調用Dispatcher.FromThread(thread) ,但要注意,這是很重要的Dispatcher 創建直到CurrentDispatcher已使用(即使你不使用后的參考)。

這種方法的缺點是不能使多個線程從隊列中選擇項目並進行工作-為此,您將不得不使用Zaches答案中描述的生產者/消費者方法。 調度程序方法使您可以將特定隊列中的工作排隊。

您為什么不只使用任務並行庫

每當您檢測到KeyUp事件時就創建一個新任務,並讓TPL擔心創建新線程。 由於它使用線程池,因此不會在每次觸發事件時創建新線程。

您遇到的問題稱為生產者/消費者問題。 您可以使用任何可用的ConcurrentCollections輕松解決它。

嘗試這樣的事情:

var queue = new ConcurrentQueue<string>();
var consume = true;

var producer = Task.Run(() => 
{
    var input = Console.ReadLine();
    while(!string.IsNullOrEmpty(input) 
    {
       queue.Enqueue(input);
       input = Console.ReadLine();         
    }
});

var consumer = Task.Run(() => 
{
    while(consume) //So we can stop the consumer
    {
        while(!queue.IsEmpty) //So we empty the queue before stopping
        {
            stringres;
            if(queue.TryDequeue(out res)) Console.WriteLine(res);
        }
    }
});

await producer;
consume = false;
await consumer;

嘗試使用任務模式庫,而不是手動啟動線程。 是你的朋友。

暫無
暫無

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

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