Skip to content

Commit 8b6a258

Browse files
committed
Convert wiki docs. #72
1 parent d516de3 commit 8b6a258

21 files changed

+278
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Supports `netstandard1.3` (including .NET 4.6, .NET Core 1.0, Xamarin.iOS 10, Xa
1111
[![AppVeyor](https://img.shields.io/appveyor/ci/StephenCleary/AsyncEx.svg?style=plastic)](https://ci.appveyor.com/project/StephenCleary/AsyncEx) [![Coveralls](https://img.shields.io/coveralls/StephenCleary/AsyncEx.svg?style=plastic)](https://coveralls.io/r/StephenCleary/AsyncEx)
1212
[![NuGet Pre Release](https://img.shields.io/nuget/vpre/Nito.AsyncEx.svg?style=plastic)](https://www.nuget.org/packages/Nito.AsyncEx/)
1313

14-
[API Docs](http://dotnetapis.com/pkg/Nito.AsyncEx)
14+
[API Docs](http://dotnetapis.com/pkg/Nito.AsyncEx) - [Overview](doc/Home.md) - [Upgrade Guide](doc/upgrade.md)
1515

1616
## Getting Started
1717

doc/ApmAsyncFactory.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Overview
2+
3+
The `ApmAsyncFactory` type enables easy interoperation with the Asynchronous Programming Model (APM).
4+
5+
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.

doc/AsyncAutoResetEvent.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Overview
2+
3+
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/]].
4+
5+
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.
6+
7+
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]] instead).
8+
9+
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]] instead).
10+
11+
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.
12+
13+
## Advanced Usage
14+
15+
You can call `WaitAsync` with an [already-cancelled `CancellationToken`](Cancellation) to attempt to acquire the `AsyncAutoResetEvent` immediately without actually entering the wait queue.

doc/AsyncCollection.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Overview
2+
3+
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]].
4+
5+
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]].

doc/AsyncConditionVariable.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Overview
2+
3+
This is an `async`-ready [[condition variable|http://en.wikipedia.org/wiki/Condition_variable]], a classical synchronization primitive in computer science without a direct .NET equivalent.
4+
5+
An `AsyncConditionVariable` is associated with a single [[AsyncLock]]. 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]].
6+
7+
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.
8+
9+
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`.
10+
11+
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`.
12+
13+
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.
14+
15+
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.

doc/AsyncContext.md

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
## Overview
2+
3+
The `AsyncContext` type provides a _context_ for executing asynchronous operations. The `await` keyword requires a _context_ to return back to. For most client programs, this is a UI context; for most server programs, this is a thread pool context. In most cases, you don't have to worry about it.
4+
5+
However, Console applications and Win32 services use the thread pool context, and `AsyncContext` or `AsyncContextThread` could be useful in those situations.
6+
7+
`AsyncContextThread` is a separate thread or task that runs an `AsyncContext`. `AsyncContextThread` does not derive from the `Thread` class. The thread begins running its `AsyncContext` immediately after creation.
8+
9+
`AsyncContextThread` will stay in its loop until it is requested to exit by another thread calling `JoinAsync`. Disposing an `AsyncContextThread` will also request it to exit, but will not wait for it to do so.
10+
11+
Normally, `AsyncContextThread` is used by windows services, but it may be used by other applications that need an independent thread with an `AsyncContext`.
12+
13+
## Console Example Using AsyncContext
14+
15+
When using `AsyncContext`, you normally just call the static `Run` method, as such:
16+
17+
```C#
18+
class Program
19+
{
20+
static async Task<int> AsyncMain()
21+
{
22+
..
23+
}
24+
25+
static int Main(string[] args)
26+
{
27+
return AsyncContext.Run(AsyncMain);
28+
}
29+
}
30+
```
31+
32+
The `Run` method will return when all asynchronous operations have been completed. Any exceptions will be unwrapped and propagated.
33+
34+
## AsyncContextThread
35+
36+
Unlike `AsyncContext`, `AsyncContextThread` provides properties that can be used to schedule tasks on that thread.
37+
38+
The `Context` property returns the `AsyncContext` being run. The `Factory` property returns a `TaskFactory` which can be used to queue work to the thread.
39+
40+
## Platform Support
41+
42+
This type is available on all platforms, but may not work due to security restrictions. This is particularly a problem on Silverlight and Windows Phone platforms.

doc/AsyncCountdownEvent.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Overview
2+
3+
This is the `async`-ready almost-equivalent of [[CountdownEvent|https://docs.microsoft.com/en-us/dotnet/api/system.threading.countdownevent]], similar to Stephen Toub's [[AsyncCountdownEvent|https://blogs.msdn.microsoft.com/pfxteam/2012/02/11/building-async-coordination-primitives-part-3-asynccountdownevent/]]. It's only an *almost* equivalent because the `AsyncCountdownEvent` does not allow itself to be reset.
4+
5+
An `AsyncCountdownEvent` starts out **unset** and becomes **set** only once, when its **count** reaches zero. Its current count can be manipulated by any other tasks up until the time it reaches zero. When the count reaches zero, all waiting tasks are released.
6+
7+
The task returned from `WaitAsync` will enter the `Completed` state when the `AsyncCountdownEvent` has counted down to zero and enters the **set** state.

doc/AsyncLazy.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
## Overview
2+
3+
The `AsyncLazy<T>` type enables [[asynchronous lazy initialization|https://blog.stephencleary.com/2012/08/asynchronous-lazy-initialization.html]], similar to [[Stephen Toub's AsyncLazy|https://blogs.msdn.microsoft.com/pfxteam/2011/01/15/asynclazyt/]].
4+
5+
An `AsyncLazy<T>` instance is constructed with a factory method. When the `AsyncLazy<T>` instance is `await`ed or its `Start` method is called, the factory method starts on a thread pool thread. The factory method is only executed once. Once the factory method has completed, all future `await`s on that instance complete immediately.

doc/AsyncLock.md

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
## Overview
2+
3+
This is the `async`-ready almost-equivalent of the `lock` keyword or the [[Mutex type|https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex]], similar to Stephen Toub's [[AsyncLock|https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/]]. It's only _almost_ equivalent because the `lock` keyword permits reentrancy, which is not currently possible to do with an `async`-ready lock.
4+
5+
An `AsyncLock` is either taken or not. The lock can be asynchronously acquired by calling `LockAsync`, and it is released by disposing the result of that task. `AsyncLock` taken an optional `CancellationToken`, which can be used to cancel the acquiring of the lock.
6+
7+
The task returned from `LockAsync` will enter the `Completed` state when it has acquired the `AsyncLock`. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the `AsyncLock` is not taken by that task.
8+
9+
## Example Usage
10+
11+
The vast majority of use cases are to just replace a `lock` statement. That is, with the original code looking like this:
12+
13+
```C#
14+
private readonly object _mutex = new object();
15+
public void DoStuff()
16+
{
17+
lock (_mutex)
18+
{
19+
Thread.Sleep(TimeSpan.FromSeconds(1));
20+
}
21+
}
22+
```
23+
24+
If we want to replace the blocking operation `Thread.Sleep` with an asynchronous equivalent, it's not directly possible because of the `lock` block. We cannot `await` inside of a `lock`.
25+
26+
So, we use the `async`-compatible `AsyncLock` instead:
27+
28+
```C#
29+
private readonly AsyncLock _mutex = new AsyncLock();
30+
public async Task DoStuffAsync()
31+
{
32+
using (await _mutex.LockAsync())
33+
{
34+
await Task.Delay(TimeSpan.FromSeconds(1));
35+
}
36+
}
37+
```
38+
39+
## Advanced Usage
40+
41+
`AsyncLock` also supports synchronous locking with the `Lock` method.
42+
43+
You can call `Lock` or `LockAsync` [with an already-cancelled `CancellationToken`](Cancellation) to attempt to acquire the `AsyncLock` immediately without actually entering the wait queue.
44+
45+
## Really Advanced Usage
46+
47+
The `AsyncLock` constructor can take an async wait queue; pass a custom wait queue to specify your own queueing logic.

doc/AsyncManualResetEvent.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Overview
2+
3+
This is the `async`-ready equivalent of [[ManualResetEvent|https://docs.microsoft.com/en-us/dotnet/api/system.threading.manualresetevent]], similar to Stephen Toub's [[AsyncManualResetEvent|https://blogs.msdn.microsoft.com/pfxteam/2012/02/11/building-async-coordination-primitives-part-1-asyncmanualresetevent/]].
4+
5+
Like other "events", an `AsyncManualResetEvent` is either **set** or **unset** at any time. An `AsyncManualResetEvent` can be changed from **unset** to **set** by calling its `Set` method, and it can be changed from **set** to **unset** by calling its `Reset` method.
6+
7+
When an `AsyncManualResetEvent` is in the **set** state, it will satisfy all waiters. Calling `Set` or `Reset` when the `AsyncManualResetEvent` is already in that state is a noop.
8+
9+
The task returned from `WaitAsync` will enter the `Completed` state when the `AsyncManualResetEvent` is in the **set** state.
10+
11+
## Advanced Usage
12+
13+
`AsyncManualResetEvent` also supports synchronous waiting with the `Wait` method.
14+
15+
You can call `Wait` with an [already-cancelled `CancellationToken`](Cancellation) to test whether the `AsyncManualResetEvent` is in the **set** state.

doc/AsyncMonitor.md

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
## Overview
2+
3+
This is the `async`-ready almost-equivalent of [[Monitor|https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor]]. It's only _almost_ equivalent because the `Monitor` type permits reentrancy, which is not currently possible to do with an `async`-ready lock.
4+
5+
An `AsyncMonitor` is an [[AsyncLock]] with a single associated [[AsyncConditionVariable]]. It is either entered or not. The `AsyncMonitor` can be asynchronously entered by calling `EnterAsync`, and you can leave it by disposing the result of that task.
6+
7+
While in the monitor, a task may decide to wait for a signal by calling `WaitAsync`. While waiting, it temporarily leaves the monitor until it receives a signal and re-enters the monitor.
8+
9+
While in the monitor, a signalling task may choose to release only a single waiter (`Pulse`) or all waiters (`PulseAll`). If there are no waiters, the notification is "lost"; it is not remembered by the `AsyncMonitor`.
10+
11+
The task returned from `EnterAsync` will enter the `Completed` state when it has entered the monitor. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the monitor is not entered by that task.
12+
13+
The task returned from `WaitAsync` will enter the `Completed` state when it receives a signal and re-enters the monitor. 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-enters the monitor.
14+
15+
Remember that from the time `WaitAsync` is called to the time when its returned task completes, the calling task has _left_ the monitor.
16+
17+
Note that the correct logic for waiting on monitor signals is to wait in a loop until the required condition is true. This is necessary because other tasks may execute between the signal and the completion of the wait.
18+
19+
## Advanced Usage
20+
21+
You can call `EnterAsync` with an [already-cancelled `CancellationToken`](Cancellation) to attempt to enter the monitor immediately without actually entering the wait queue.

doc/AsyncProducerConsumerQueue.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Overview
2+
3+
An `AsyncProducerConsumerQueue` is a queue of items that provides `async`-compatible *Enqueue* and *Dequeue* operations. [[AsyncCollection]] is more flexible than this type, but it is also more complex.

doc/AsyncReaderWriterLock.md

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
## Overview
2+
3+
This is the `async`-ready almost-equivalent of the the [[ReaderWriterLockSlim type|https://docs.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlockslim]], similar to Stephen Toub's [[AsyncReaderWriterLock|https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-7-asyncreaderwriterlock/]]. It's only _almost_ equivalent because the `ReaderWriterLockSlim` can be constructed in a way which allows reentrancy, and this is not currently possible to do with an `async`-ready lock.
4+
5+
There are two types of locks that can be taken on an `AsyncReaderWriterLock`:
6+
* Write locks, which are fully exclusive. They do not allow other locks of any kind.
7+
* Read locks, which permit other read locks but exclude write locks.
8+
9+
Write and read locks may be asynchronously acquired by calling `WriterLockAsync` or `ReaderLockAsync`. These locks are released by disposing the result of the returned task.
10+
11+
The tasks returned from `WriterLockAsync` and `ReaderLockAsync` will enter the `Completed` state when they have acquired the `AsyncReaderWriterLock`. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the `AsyncReaderWriterLock` is not taken by that task.
12+
13+
## Advanced Usage
14+
15+
You can call `WriterLockAsync` and `ReaderLockAsync` with an [already-cancelled `CancellationToken`](Cancellation) to attempt to acquire the `AsyncReaderWriterLock` immediately without actually entering the wait queue.

doc/AsyncSemaphore.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## Overview
2+
3+
This is the `async`-ready equivalent of [[Semaphore|https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphore]], similar to Stephen Toub's [[AsyncSempahore|https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-5-asyncsemaphore/]]. Alternatively, you can use the [[SemaphoreSlim|https://docs.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim]] class, which is `async`-ready on modern platforms.
4+
5+
An `AsyncSemaphore` keeps a count, which is the number of open "slots" it has available to satisfy waiters. Any thread may increase the number of slots available by calling `Release`.
6+
7+
The task returned from `WaitAsync` will enter the `Completed` state when the `AsyncSemaphore` has given it a slot. That same task will enter the `Canceled` state if the `CancellationToken` is signaled before the wait is satisfied; in that case, the `AsyncSemaphore` does not lose a slot.
8+
9+
## Advanced Usage
10+
11+
You can call `WaitAsync` with an [already-cancelled `CancellationToken`](Cancellation) to attempt to acquire a slot from the `AsyncSemaphore` immediately without actually entering the wait queue.

doc/Cancellation.md

Whitespace-only changes.

doc/ExceptionHelpers.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
## Overview
2+
3+
There is one static method on the `ExceptionHelpers` type: `PrepareForRethrow`.
4+
5+
The purpose of this method is to preserve the original stack trace of the exception so that it is not overwritten when the exception is rethrown.
6+
7+
The return value of this method should always be thrown immediately; that is, every call to this method should look like this:
8+
9+
```C#
10+
Exception ex = ...; // get saved exception
11+
throw ExceptionHelpers.PrepareForRethrow(ex);
12+
```
13+
14+
`PrepareForRethrow` uses [[ExceptionDispatchInfo|https://docs.microsoft.com/en-us/dotnet/api/system.runtime.exceptionservices.exceptiondispatchinfo]].

0 commit comments

Comments
 (0)