使用TPL/C#5/.NET 4.0进行非阻塞等待

本文关键字:等待 TPL C#5 NET 使用 | 更新日期: 2023-09-27 18:29:56

我有一些常用代码需要重构回C#5(我最初的问题是C#4)/.NET4.0,这样我就可以在更多的项目中共享它。最大的影响是不使用async/await并切换回TPL并使用ContinueWith()

有没有一种方法可以在同步对象上实现无阻塞等待,而无需将其放入后台线程中进行模拟?计时器我可以使用TaskCompletionSource,所以我在那里很好。

SemaphoreSlim mutex = new SemaphoreSlim(1);
await mutex.WaitAsync(); // <-- how to get a Task that completes on mutex.Wait()

例如

mutex.WaitInATask().ContinueWith(...

UPDATE我决定不以C#4.0为目标(但仍然以.NET 4.0框架为目标),因为我更关心程序集,而不是能够在项目之间共享的源代码。

我决定使用Microsoft.Bcl.Async,Stephen Cleary的AsyncEx,目标.NET 4.0框架,并将构建C#版本设置为5.0(以支持Async/await)。这可能需要VS2015进行编译,但程序集(以及依赖项)将以.NET 4.0为目标。

这种方法的额外好处是减少了从async/awaitContinueWith()的重构代码,这将减少一路上的错误。。。

使用TPL/C#5/.NET 4.0进行非阻塞等待

通过受问题评论启发的研究,我得出了以下答案:

首先,我放弃了编译器为C#4.0的要求。这意味着二进制文件仍将与.NET 4.0 Framework兼容,但源代码将需要支持C#5.0的编译器(例如Visual Studio 2015)。我可以与遗留项目共享二进制文件,但不能共享源代码。

在.NET 4.0 Framework中进行非阻塞等待的最干净的方法是:

  1. 创建一个以.NET 4.0 Framework为目标的类库项目(使用新项目执行此操作,以避免在创建后切换框架版本时引用无法正确更新)

  2. 将C#版本(在VS 2015中,项目属性/内部版本/高级)设置为5.0。这启用了async/await语法,这意味着我不需要将所有的async/await重新编码成丑陋、复杂的.ContineWith()嵌套和破解。

  3. 添加NuGet包Nito.AncEx和Microsoft.Bcl.Async(后者与前者一起提供,但我发现我需要包含比Nito.AsyncEx作为依赖项所需的更新版本的Microsoft.Bcl.异步,所以我首先添加了Microsoft.Bcl.sync)。

  4. 使用WaitAsync()转换任何同步对象以使用AsyncEx版本,例如SemaphoreSlim=>AsyncSemaphore。

至少,这允许我通过引用旧.NET 4.0项目中的二进制文件来重用一些有价值的功能,这些项目目前由于各种原因无法升级。