0

这是我想做的事情:

  1. 在我的主线程(控制 UI)中创建一个工作线程。
  2. 工作线程一直运行直到被主线程关闭(仅在整个应用程序关闭时才会发生)。
  3. 主线程监听keyup,但向工作线程发送一个事件以异步处理keyup(避免阻塞UI)。
  4. 处理完 keyup 后,工作线程会更新 UI。

到目前为止,我只是在每次有 keyup 时创建一个新线程,但这种方式似乎开销太大。

据我所知,我应该使用 BackgroundWorker 类,但我看到的示例似乎启动了一个后台工作程序,在主线程中继续使用非阻塞 UI,并在完成后从 BackgroundWorker 更新 UI - 即完全正确和我已经在做的一样。

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

4

3 回答 3

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()and创建的任务Task.Factory.StartNew()

我不是 100% 确定有必要调用thread.Join(),但我宁愿确定线程已被关闭。如果您使用的是Task呼叫task.Wait()

获取 a 的另一种方法Dispatcher是调用,但重要的是Dispatcher.FromThread(thread)要注意 a在使用之前不会创建(即使您以后不使用引用)。DispatcherCurrentDispatcher

这种方法的一个缺点是它不能用于让多个线程从队列中挑选项目并进行工作 - 因为您将不得不使用 Zaches 回答中描述的生产者/消费者。调度程序方法允许您在特定主题中排队工作。

于 2015-08-06T11:24:24.503 回答
0

你为什么不直接使用任务并行库

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

于 2013-10-03T09:18:24.373 回答
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;

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

于 2013-10-03T09:48:20.197 回答