外部函数调用阻止UI线程

时间:2015-03-04 00:03:02

标签: c# multithreading .net-4.0 task

我正在开发一个通过以太网与运动控制器通信的应用程序。

要连接到控制器,我使用供应商提供的库,连接你创建一个控制器实例,然后告诉它连接,这有机会阻塞几秒钟(没有可控的超时),如果没有控制器存在。这导致UI冻结。

为了避免这种情况,我想我可以使用Tasks在不同的线程中运行连接。

ConnectionTask = Task.Factory.StartNew(() =>
{
    try
    {
        RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
        RMC.Connect();
    }
    catch
    {
        this.logger.Log("Failed to connect");
    }
}, TaskCreationOptions.LongRunning);

这没有任何效果,UI仍然会锁定。

我认为我正在正确使用它们,好像我用下面的代码替换它,UI很好,即使单独的线程在消息出来之前需要几秒钟。

ConnectionTask = Task.Factory.StartNew(() =>
{
    int x = 1;
    while (x != 0) x++;
    this.logger.Log("Failed to connect");
}, TaskCreationOptions.LongRunning);

有没有什么方法可以识别发生的事情并阻止我不了解内部工作的调用来锁定UI线程。

1 个答案:

答案 0 :(得分:1)

使用async / await,类似于:

public async void MyButton_Click(object sender, EventArgs e)
{
    await CreateEthernetLink();

    this.logger.Log("Connected!");
}

private async Task CreateEthernetLink()
{ 
    var task = Task.Run(() => {
        try
        {
            RMCLink rmc = RMCLink.CreateEthernetLink(DeviceType.RMC70, "192.168.0.55");
            rmc.Connect();
        }
        catch
        {
            this.logger.Log("Failed to connect");
        }});

     await task;
 }

await将捕获当前线程(或SynchronizationContext - 在这种情况下是被阻止的UI线程)并在异步工作完成后恢复它。

因此,在幕后为您处理线程,除了在执行连接时应用程序不再冻结这一事实外,您应该注意到应用程序没有任何区别。

编辑:我还在您的代码中注意到您正在初始化 rmc ,但在 RMC 上调用connect。我不认为这是正确的。