C#工作线程与事件驱动的工作,没有关闭

时间:2013-10-03 09:10:34

标签: c# backgroundworker

这是我想做的事情:

  1. 在我的主线程中创建一个工作线程(控制UI)。
  2. 工作线程一直运行,直到被主线程关闭(只有当整个应用程序关闭时才会发生)。
  3. 主线程侦听keyup,但是向工作线程发送一个事件以异步处理keyup(以避免阻塞UI)。
  4. 工作线程在处理完keyup时更新UI。
  5. 到目前为止,我每次创建一个新的线程时都会创建一个新的线程,但是这样的开销似乎太多了。

    据我所知,我应该使用BackgroundWorker类,但我看到的示例似乎启动了后台工作程序,在主线程中继续使用非阻塞UI,并在完成时从BackgroundWorker更新UI - 就像我现在一样。

    如何使工作线程在没有工作要做的时候继续运行和休眠?

3 个答案:

答案 0 :(得分:1)

虽然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答案中描述的生产者/消费者。调度程序方法允许您在特定的 thead中排队工作。

答案 1 :(得分:0)

为什么不使用Task Parallel Library

每当检测到KeyUp事件时创建一个新任务,让TPL担心创建新线程。由于它使用线程池,因此每次触发事件时都不会创建新线程。

答案 2 :(得分:0)

您遇到的问题称为生产者/消费者问题。您可以使用任何可用的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;

尝试使用任务模式库而不是手动启动线程。这是你的朋友。