继续代码在另一个线程上

时间:2015-09-22 07:58:00

标签: c# .net wpf async-await

我正在编写一些在UI线程上调用的代码,在另一个线程(不是ThreadPool,但每次都是相同的线程)上调用一些代码,然后在UI线程上恢复。我想就最好的异步方式做一些建议。

EnsureThread方法的复杂性是因为另一个线程每次都必须是同一个线程,并且必须是运行Dispatcher的STA。这是因为我需要使用MCI,但不希望它在UI线程上运行。见https://stackoverflow.com/a/32711239/420159

我像这样创建第二个线程:

private static void EnsureThread()
{
    if (eventLoopThread != null)
    {
        return;
    }

    lock (eventLoopLock)
    {
        if (eventLoopThread == null)
        {
            var lck = new EventWaitHandle(false, EventResetMode.ManualReset);

            var t = new Thread(() =>
            {
                try
                {
                    // create dispatcher and sync context
                    var d = Dispatcher.CurrentDispatcher;
                    var context = new DispatcherSynchronizationContext(d);
                    SynchronizationContext.SetSynchronizationContext(context);

                    // create taskfactory
                    eventLoopFactory = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
                    eventLoopDispatcher = d;
                }
                finally
                {
                    lck.Set();
                }

                // run the event loop
                Dispatcher.Run();
            });
            t.SetApartmentState(ApartmentState.STA);
            t.IsBackground = true;
            t.Start();

            lck.WaitOne();
            lck.Dispose();

            eventLoopThread = t;
        }
    }
}

然后我像这样调用第二个线程:

async void button_click(...)
{
    // do something 1

    await eventLoopFactory.StartNew(()=>
    {
        // do something 2
    });

    // do something 3
}

有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

如果要在ThreadPool

的主题上运行委托,则不需要使用线程工厂

只需使用

        await Task.Run(() =>
        {
            // do something 2
        });

这样,您就不需要在事件循环线程上运行// do something代码,但它将在线程池中的可用线程上运行。

你不应该自己创建第二个帖子。线程池是正确的工具,因为它将以非常有效的方式回收空闲线程。

答案 1 :(得分:1)

您的Button_Click似乎已经做了太多事情,您应该首先将此方法拆分为单独的方法。

async void Button_Click(...)
{
    await DoSomething1();
    await DoSomething2();
    await DoSomething3();
}

现在,您的其他方法将如下所示:

async Task DoSomething1()
{
    await Task.Run(() =>
    {
        ...
    });
}

这将允许您的Button_Click方法异步执行这些任务(按顺序)并保持您的UI响应。