Skip to content

Commit

Permalink
Merge pull request #137 from icarus-consulting/i136-use-strong-named-…
Browse files Browse the repository at this point in the history
…references

Use strong named references
  • Loading branch information
DFU398 authored Mar 17, 2023
2 parents c162dc2 + 2d0c5ce commit c695c99
Show file tree
Hide file tree
Showing 174 changed files with 14,906 additions and 23 deletions.
4 changes: 4 additions & 0 deletions ThirdParty/AsyncEx/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# CA1068: CancellationToken parameters must come last
dotnet_diagnostic.CA1068.severity = silent
Binary file added ThirdParty/AsyncEx/AsyncEx.128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions ThirdParty/AsyncEx/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Contributing to AsyncEx

:+1: Thanks for taking the time to contribute! :+1:

If you have encountered a bug (or just have a question on how to use the library), feel free to open an issue immediately. If reporting a bug, please include the version of AsyncEx you are using, your runtime platform and version, and code to reproduce the problem.

If you have an idea for code, or would like to contribute some code, the first step is to review the [design guidelines](doc/design.md). If your code falls within those guidelines, the next step is to open an issue for discussion. Finally, if the idea has been discussed and sounds like a good fit for AsyncEx, feel free to open a pull request. I know this is slow and annoying, but it makes me sad to close PRs that people put a lot of work into but don't fit in well with AsyncEx.

Our code of conduct is: be nice. Seriously, I don't think we need lawyer language. Just be nice. :blush:

That's it! Thanks again for contributing! :+1:
21 changes: 21 additions & 0 deletions ThirdParty/AsyncEx/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2014 StephenCleary

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
102 changes: 102 additions & 0 deletions ThirdParty/AsyncEx/Nito.AsyncEx.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30517.126
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx.Tasks", "src\Nito.AsyncEx.Tasks\Nito.AsyncEx.Tasks.csproj", "{3817C77D-0C9D-4B57-8C00-27C7BC398E61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx.Coordination", "src\Nito.AsyncEx.Coordination\Nito.AsyncEx.Coordination.csproj", "{8C44A01D-60CD-4221-A94B-86EF177D9061}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx.Interop.WaitHandles", "src\Nito.AsyncEx.Interop.WaitHandles\Nito.AsyncEx.Interop.WaitHandles.csproj", "{B48EF95C-B838-453D-8F3D-3B12F948C29E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx.Oop", "src\Nito.AsyncEx.Oop\Nito.AsyncEx.Oop.csproj", "{47B3CBF6-BF03-4AD0-8795-4060A8AE0959}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx.Context", "src\Nito.AsyncEx.Context\Nito.AsyncEx.Context.csproj", "{C3193836-09A1-401D-A232-CC4A7431C2B4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{89C049C2-1211-4BB8-A2FA-D8ECB60676A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncEx.Context.UnitTests", "test\AsyncEx.Context.UnitTests\AsyncEx.Context.UnitTests.csproj", "{12786A78-4A97-487A-BFB7-E79123460E61}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncEx.Coordination.UnitTests", "test\AsyncEx.Coordination.UnitTests\AsyncEx.Coordination.UnitTests.csproj", "{E8CADD51-1B46-439E-801C-83656181B8A7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncEx.Interop.WaitHandles.UnitTests", "test\AsyncEx.Interop.WaitHandles.UnitTests\AsyncEx.Interop.WaitHandles.UnitTests.csproj", "{8EF01C49-665F-481A-AF19-1335292BE59A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncEx.Oop.UnitTests", "test\AsyncEx.Oop.UnitTests\AsyncEx.Oop.UnitTests.csproj", "{F85ECD63-74E0-49EA-910F-0A27A915FDA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsyncEx.Tasks.UnitTests", "test\AsyncEx.Tasks.UnitTests\AsyncEx.Tasks.UnitTests.csproj", "{8B6341C7-AF1F-4713-B7C9-D097B2378142}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nito.AsyncEx", "src\Nito.AsyncEx\Nito.AsyncEx.csproj", "{EC1B4E56-E379-44BE-8662-77C1CB9E773A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3817C77D-0C9D-4B57-8C00-27C7BC398E61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3817C77D-0C9D-4B57-8C00-27C7BC398E61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3817C77D-0C9D-4B57-8C00-27C7BC398E61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3817C77D-0C9D-4B57-8C00-27C7BC398E61}.Release|Any CPU.Build.0 = Release|Any CPU
{8C44A01D-60CD-4221-A94B-86EF177D9061}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8C44A01D-60CD-4221-A94B-86EF177D9061}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8C44A01D-60CD-4221-A94B-86EF177D9061}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8C44A01D-60CD-4221-A94B-86EF177D9061}.Release|Any CPU.Build.0 = Release|Any CPU
{B48EF95C-B838-453D-8F3D-3B12F948C29E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B48EF95C-B838-453D-8F3D-3B12F948C29E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B48EF95C-B838-453D-8F3D-3B12F948C29E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B48EF95C-B838-453D-8F3D-3B12F948C29E}.Release|Any CPU.Build.0 = Release|Any CPU
{47B3CBF6-BF03-4AD0-8795-4060A8AE0959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{47B3CBF6-BF03-4AD0-8795-4060A8AE0959}.Debug|Any CPU.Build.0 = Debug|Any CPU
{47B3CBF6-BF03-4AD0-8795-4060A8AE0959}.Release|Any CPU.ActiveCfg = Release|Any CPU
{47B3CBF6-BF03-4AD0-8795-4060A8AE0959}.Release|Any CPU.Build.0 = Release|Any CPU
{C3193836-09A1-401D-A232-CC4A7431C2B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3193836-09A1-401D-A232-CC4A7431C2B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3193836-09A1-401D-A232-CC4A7431C2B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3193836-09A1-401D-A232-CC4A7431C2B4}.Release|Any CPU.Build.0 = Release|Any CPU
{12786A78-4A97-487A-BFB7-E79123460E61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{12786A78-4A97-487A-BFB7-E79123460E61}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12786A78-4A97-487A-BFB7-E79123460E61}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12786A78-4A97-487A-BFB7-E79123460E61}.Release|Any CPU.Build.0 = Release|Any CPU
{E8CADD51-1B46-439E-801C-83656181B8A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E8CADD51-1B46-439E-801C-83656181B8A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E8CADD51-1B46-439E-801C-83656181B8A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E8CADD51-1B46-439E-801C-83656181B8A7}.Release|Any CPU.Build.0 = Release|Any CPU
{8EF01C49-665F-481A-AF19-1335292BE59A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8EF01C49-665F-481A-AF19-1335292BE59A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8EF01C49-665F-481A-AF19-1335292BE59A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8EF01C49-665F-481A-AF19-1335292BE59A}.Release|Any CPU.Build.0 = Release|Any CPU
{F85ECD63-74E0-49EA-910F-0A27A915FDA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F85ECD63-74E0-49EA-910F-0A27A915FDA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F85ECD63-74E0-49EA-910F-0A27A915FDA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F85ECD63-74E0-49EA-910F-0A27A915FDA2}.Release|Any CPU.Build.0 = Release|Any CPU
{8B6341C7-AF1F-4713-B7C9-D097B2378142}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8B6341C7-AF1F-4713-B7C9-D097B2378142}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8B6341C7-AF1F-4713-B7C9-D097B2378142}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8B6341C7-AF1F-4713-B7C9-D097B2378142}.Release|Any CPU.Build.0 = Release|Any CPU
{EC1B4E56-E379-44BE-8662-77C1CB9E773A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC1B4E56-E379-44BE-8662-77C1CB9E773A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC1B4E56-E379-44BE-8662-77C1CB9E773A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC1B4E56-E379-44BE-8662-77C1CB9E773A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{3817C77D-0C9D-4B57-8C00-27C7BC398E61} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
{8C44A01D-60CD-4221-A94B-86EF177D9061} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
{B48EF95C-B838-453D-8F3D-3B12F948C29E} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
{47B3CBF6-BF03-4AD0-8795-4060A8AE0959} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
{C3193836-09A1-401D-A232-CC4A7431C2B4} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
{12786A78-4A97-487A-BFB7-E79123460E61} = {89C049C2-1211-4BB8-A2FA-D8ECB60676A1}
{E8CADD51-1B46-439E-801C-83656181B8A7} = {89C049C2-1211-4BB8-A2FA-D8ECB60676A1}
{8EF01C49-665F-481A-AF19-1335292BE59A} = {89C049C2-1211-4BB8-A2FA-D8ECB60676A1}
{F85ECD63-74E0-49EA-910F-0A27A915FDA2} = {89C049C2-1211-4BB8-A2FA-D8ECB60676A1}
{8B6341C7-AF1F-4713-B7C9-D097B2378142} = {89C049C2-1211-4BB8-A2FA-D8ECB60676A1}
{EC1B4E56-E379-44BE-8662-77C1CB9E773A} = {FBBB0AFC-0473-47AC-A5F8-235524DF8A8A}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B4638CC6-F431-4430-8FD0-C51DF9E9B77F}
EndGlobalSection
EndGlobal
89 changes: 89 additions & 0 deletions ThirdParty/AsyncEx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
![Logo](AsyncEx.128.png)

# AsyncEx

A helper library for async/await.

Note: This README is for AsyncEx v5 (the current version). For AsyncEx v4, see [here](https://github.com/StephenCleary/AsyncEx/tree/v4).

Supports `netstandard1.3` (including .NET 4.6, .NET Core 1.0, Xamarin.iOS 10, Xamarin.Android 7, Mono 4.6, and Universal Windows 10).

[![NuGet Pre Release](https://img.shields.io/nuget/vpre/Nito.AsyncEx.svg)](https://www.nuget.org/packages/Nito.AsyncEx/) [![netstandard 1.3](https://img.shields.io/badge/netstandard-1.3-brightgreen.svg)](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) [![netstandard 2.0](https://img.shields.io/badge/netstandard-2.0-brightgreen.svg)](https://docs.microsoft.com/en-us/dotnet/standard/net-standard) [![Code Coverage](https://coveralls.io/repos/github/StephenCleary/AsyncEx/badge.svg?branch=master)](https://coveralls.io/github/StephenCleary/AsyncEx?branch=master) [![Build status](https://ci.appveyor.com/api/projects/status/37edy7t2g377rojs/branch/master?svg=true)](https://ci.appveyor.com/project/StephenCleary/asyncex/branch/master)

[![API docs](https://img.shields.io/badge/reference%20docs-api-blue.svg)](http://dotnetapis.com/pkg/Nito.AsyncEx)

[Overview](doc/Home.md) - [Upgrade Guide](doc/upgrade.md)

## Getting Started

Install the [NuGet package](http://www.nuget.org/packages/Nito.AsyncEx).

## AsyncLock

A lot of developers start using this library for `AsyncLock`, an async-compatible mutual exclusion mechanism. Using `AsyncLock` is straightforward:

```C#
private readonly AsyncLock _mutex = new AsyncLock();
public async Task UseLockAsync()
{
// AsyncLock can be locked asynchronously
using (await _mutex.LockAsync())
{
// It's safe to await while the lock is held
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
```

`AsyncLock` also fully supports cancellation:

```C#
public async Task UseLockAsync()
{
// Attempt to take the lock only for 2 seconds.
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(2));

// If the lock isn't available after 2 seconds, this will
// raise OperationCanceledException.
using (await _mutex.LockAsync(cts.Token))
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
```

`AsyncLock` also has a synchronous API. This permits some threads to acquire the lock asynchronously while other threads acquire the lock synchronously (blocking the thread).

```C#
public async Task UseLockAsync()
{
using (await _mutex.LockAsync())
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
}

public void UseLock()
{
using (_mutex.Lock())
{
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}
```

## Other Coordination Primitives

`AsyncLock` is just the beginning. The AsyncEx library contains a full suite of coordination primitives: `AsyncManualResetEvent`, `AsyncAutoResetEvent`, `AsyncConditionVariable`, `AsyncMonitor`, `AsyncSemaphore`, `AsyncCountdownEvent`, and `AsyncReaderWriterLock`.

## More Stuff

There's quite a few other helpful types; see [the docs for full details](doc)

## Infrequently Asked Questions

### Older Platforms

[AsyncEx v4](https://github.com/StephenCleary/AsyncEx/tree/v4) supported .NET 4.0, Windows Store 8.1, Windows Phone Silverlight 8.0, Windows Phone Applications 8.1, and Silverlight 5.0. Support for these platforms has been dropped with AsyncEx v5.

AsyncEx v3 supported Windows Store 8.0, Windows Phone Silverlight 7.5, and Silverlight 4.0. Support for these platforms has been dropped with AsyncEx v4.
5 changes: 5 additions & 0 deletions ThirdParty/AsyncEx/doc/ApmAsyncFactory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Overview

The `ApmAsyncFactory` type enables easy interoperation with the Asynchronous Programming Model (APM).

APM is the old-style approach to asynchronous programming that used `Begin`/`End` method pairs with `IAsyncResult` representing the asynchronous operation. The `FromApm` methods on `ApmAsyncFactory` convert from APM to TAP, and the `ToBegin` and `ToEnd` methods convert from TAP to APM.
15 changes: 15 additions & 0 deletions ThirdParty/AsyncEx/doc/AsyncAutoResetEvent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Overview

This is the `async`-ready equivalent of [AutoResetEvent](https://docs.microsoft.com/en-us/dotnet/api/system.threading.autoresetevent), similar to Stephen Toub's [AsyncAutoResetEvent](https://blogs.msdn.microsoft.com/pfxteam/2012/02/11/building-async-coordination-primitives-part-2-asyncautoresetevent/).

Like other "events", an `AsyncAutoResetEvent` is either **set** or **unset** at any time. An `AsyncAutoResetEvent` can be changed from **unset** to **set** by calling its `Set` method. When a `WaitAsync` operation completes, the `AsyncAutoResetEvent` is automatically changed back to the **unset** state.

Moving an `AsyncAutoResetEvent` to the **set** state can only satisfy a single waiter. If there are multiple waiters when `Set` is called, only one will be released. (If this is not the behavior you want, use [AsyncManualResetEvent](AsyncManualResetEvent.md) instead).

When an `AsyncAutoResetEvent` is in the **set** state (with no waiters), `Set` is a noop. The `AsyncAutoResetEvent` will not remember how many times `Set` is called; those extra signals are "lost". (If this is not the behavior you want, use [AsyncSemaphore](AsyncSemaphore.md) instead).

The task returned from `WaitAsync` will enter the `Completed` state when the wait is satisfied and the `AsyncAutoResetEvent` has been automatically reset. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the `AsyncAutoResetEvent` has not been automatically reset.

## Advanced Usage

You can call `WaitAsync` with an [already-cancelled `CancellationToken`](Cancellation.md) to attempt to acquire the `AsyncAutoResetEvent` immediately without actually entering the wait queue.
5 changes: 5 additions & 0 deletions ThirdParty/AsyncEx/doc/AsyncCollection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Overview

An `AsyncCollection` is an `async`-compatible wrapper around [IProducerConsumerCollection](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.iproducerconsumercollection-1) collections such as [ConcurrentQueue](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentqueue-1) or [ConcurrentBag](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentbag-1).

This makes `AsyncCollection` an `async` near-equivalent of [BlockingCollection](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.blockingcollection-1), which is a blocking wrapper around [IProducerConsumerCollection](https://docs.microsoft.com/en-us/dotnet/api/system.collections.concurrent.iproducerconsumercollection-1).
15 changes: 15 additions & 0 deletions ThirdParty/AsyncEx/doc/AsyncConditionVariable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
## Overview

This is an `async`-ready [condition variable](https://en.wikipedia.org/wiki/Condition_variable), a classical synchronization primitive in computer science without a direct .NET equivalent.

An `AsyncConditionVariable` is associated with a single [AsyncLock](AsyncLock.md). All methods on the `AsyncConditionVariable` type ***require*** that you hold the associated lock before calling them. There's no runtime checks for these preconditions because there is no way to check them; you'll just have to be careful. I recommend you combine the `AsyncLock` with its associated `AsyncConditionVariable` instances into a higher-level custom lock/signal system. Note that the simple case of a single `AsyncLock` with a single `AsyncConditionVariable` is equivalent to [AsyncMonitor](AsyncMonitor.md).

Waiting on an `AsyncConditionVariable` enables an `async` method to (asynchronously) wait for some condition to become true. While waiting, that `async` method gives up the `AsyncLock`. When the condition becomes true, another `async` method notifies the `AsyncConditionVariable`, which re-acquires the `AsyncLock` and releases the waiter.

When notifying the `AsyncConditionVariable`, the notifying task may choose to release only a single waiter (`Notify`) or all waiters (`NotifyAll`). If there are no waiters, the notification is "lost"; it is not remembered by the `AsyncConditionVariable`.

The task returned from `WaitAsync` will enter the `Completed` state when it receives a notification and re-acquires the `AsyncLock`. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the task will wait to enter the `Canceled` state until it re-acquires the `AsyncLock`.

Remember that from the time `WaitAsync` is called to the time when its returned task completes, the `AsyncLock` is _not_ held by the calling task.

Note that the correct logic for condition variables is to wait in a loop until the required condition is true. This is necessary because other tasks may execute between the notification and the completion of the wait.
Loading

0 comments on commit c695c99

Please sign in to comment.