在另一个线程上继续执行代码

本文关键字:执行 代码 继续 另一个 线程 | 更新日期: 2023-09-27 18:13:57

我正在编写一些在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
}

有更好的方法吗?

在另一个线程上继续执行代码

如果你想在ThreadPool的线程上运行委托,你真的不需要使用线程工厂

只使用

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

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

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

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

async void Button_Click(...)
{
    await DoSomething1();
    await DoSomething2();
    await DoSomething3();
}
现在,你的其他方法看起来像这样:
async Task DoSomething1()
{
    await Task.Run(() =>
    {
        ...
    });
}

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