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 而不是线程安全库的主要内容,如果未能解决你的问题,请参考以下文章
csharp csharp_test_taskcompletionsource_and_threads.cs
C# 之 多线程 -- 任务概念以及使用示例 ( Task | TaskCompletionSource | Async | Await )