TaskCompletionSource 而不是线程安全库

Posted

技术标签:

【中文标题】TaskCompletionSource 而不是线程安全库【英文标题】:TaskCompletionSource and not thread-safe library 【发布时间】:2021-08-08 18:45:17 【问题描述】:

我有 C# avalonia 应用程序通过开发人员提供的 SDK 使用了一些非线程安全的库。更具体地说是Windows Zoom SDK。一些 SDK 功能是基于事件驱动模式构建的。调用 SDK 方法后,应用程序必须等待执行结果回调到达。因此,基于任务的异步模式被应用到使用 TaskCompletionSource 的应用程序中(请参见下面的代码)。

在应用程序中应用 async/await 模式后,SDK 无法正常工作 (details)。但是,这个问题没有讨论使用 Zoom SDK。问题是使用 async/await 模式如何可能导致某些非线程安全库(或 SDK)的错误行为?

SDK 封装方法:

public async Task<bool> SdkMethodAAsync(string parameter)

    try
    
        this.sdkService.SdkMethodA(parameter);

        this.tcs = new TaskCompletionSource<bool>();
        return await this.tcs.Task;
    
    catch (Exception)
    
        return false;
    
    
    return false;
    

SDK 回调处理程序:

    public void OnMethodAReturn(MethodAResult ret)
    
        // here some property can also be changed 
        // and which will trigger an event on which SDK calls can be made to         

        this.tcs.TrySetResult(ret == MethodAResult.METHODA_SUCCESS);
    

高级代码:

    public async Task StartAsync(string parameter1, string parameter2)
    
        var resultMethodA = await SdkMethodAAsync(parameter1);
        var resultMethodB = await SdkMethodBAsync(parameter2);
    

【问题讨论】:

到底有什么问题?您是否看到 SdkMethodBAsync 在错误的线程上被调用? @canton7 不,所有后续调用都在主线程上进行。这些调用(转换为 TAP)是初始化、身份验证和登录方法。所以接下来,SDK似乎处于不正确的状态(未正确处理用户,我收到意外回调,某些方法未正确执行)。在没有 TAP 的应用程序版本中,一切正常。其余程序相同。但我也承认 TAP 可能不是问题。也许我的问题更具理论性。会有哪些陷阱? 【参考方案1】:

第一个明显的问题是在进行方法调用后更新任务完成源。该方法可能会同步完成,这会打乱您的模式。改成

    this.tcs = new TaskCompletionSource<bool>();
    this.sdkService.SdkMethodA(parameter);        
    return await this.tcs.Task;

您可能要防止的另一件事是并发调用。说有人试图做

    var mA = SdkMethodAAsync(parameter1);
    var mB = SdkMethodBAsync(parameter2);
    await Task.WhenAll(mA, mB);

如果SDK不允许并发调用,这将是一个错误,但是否会报告错误,或者它是否会导致意外行为并不明显。所以你可能想建立一些机制来检测这种情况并以某种方式处理它。

另一件事可能并不明显

this.tcs.TrySetResult(ret == MethodAResult.METHODA_SUCCESS);

这将使任务总是成功,返回值告诉它实际上是否成功。我本来希望根据方法结果将任务置于成功/失败/取消状态。这也可能允许返回值或错误消息,而不是简单地成功/失败。

【讨论】:

以上是关于TaskCompletionSource 而不是线程安全库的主要内容,如果未能解决你的问题,请参考以下文章

TaskCompletionSource的使用场景

csharp csharp_test_taskcompletionsource_and_threads.cs

C# 之 多线程 -- 任务概念以及使用示例 ( Task | TaskCompletionSource | Async | Await )

GeometryRenderer 为啥渲染线,而不是三角形

文本下划线在文本上方而不是下方显示线

我正在尝试将三次函数添加到图形而不是线性趋势线