Asynchronous Programming Patterns
Asynchronous Programming Patterns
Asynchronous Programming Patterns
The .NET Framework provides three patterns for performing asynchronous operations:
Asynchronous Programming Model (APM) pattern (also called the IAsyncResult pattern), where
asynchronous operations require Begin and End methods (for example, BeginWrite and EndWrite for
asynchronous write operations). This pattern is no longer recommended for new development. For more
information, see Asynchronous Programming Model (APM).
Event-based Asynchronous Pattern (EAP), which requires a method that has the Async suffix, and also
requires one or more events, event handler delegate types, and EventArg -derived types. EAP was
introduced in the .NET Framework 2.0. It is no longer recommended for new development. For more
information, see Event-based Asynchronous Pattern (EAP).
Task-based Asynchronous Pattern (TAP), which uses a single method to represent the initiation and
completion of an asynchronous operation. TAP was introduced in the .NET Framework 4 and is the
recommended approach to asynchronous programming in the .NET Framework. The async and await
keywords in C# and the Async and Await operators in Visual Basic Language add language support for TAP.
For more information, see Task-based Asynchronous Pattern (TAP).
Comparing Patterns
For a quick comparison of how the three patterns model asynchronous operations, consider a Read method that
reads a specified amount of data into a provided buffer starting at a specified offset:
The APM counterpart of this method would expose the BeginRead and EndRead methods:
The EAP counterpart would expose the following set of types and members:
The TAP counterpart would expose the following single ReadAsync method:
public class MyClass
{
public Task<int> ReadAsync(byte [] buffer, int offset, int count);
}
For a comprehensive discussion of TAP, APM, and EAP, see the links provided in the next section.
Related topics
TITLE DESCRIPTION
Asynchronous Programming Model (APM) Describes the legacy model that uses the IAsyncResult
interface to provide asynchronous behavior. This model is no
longer recommended for new development.
Event-based Asynchronous Pattern (EAP) Describes the event-based legacy model for providing
asynchronous behavior. This model is no longer
recommended for new development.
Task-based Asynchronous Pattern (TAP) Describes the new asynchronous pattern based on the
System.Threading.Tasks namespace. This model is the
recommended approach to asynchronous programming in the
.NET Framework 4 and later versions.
See also
Asynchronous programming in C#
Async Programming in F#
Asynchronous Programming with Async and Await (Visual Basic)
Task-based Asynchronous Pattern (TAP)
8/26/2017 • 12 min to read • Edit Online
Exceptions
An asynchronous method should raise an exception to be thrown out of the asynchronous method call only in
response to a usage error. Usage errors should never occur in production code. For example, if passing a null
reference ( Nothing in Visual Basic) as one of the method’s arguments causes an error state (usually represented
by an ArgumentNullException exception), you can modify the calling code to ensure that a null reference is never
passed. For all other errors, exceptions that occur when an asynchronous method is running should be assigned to
the returned task, even if the asynchronous method happens to complete synchronously before the task is
returned. Typically, a task contains at most one exception. However, if the task represents multiple operations (for
example, WhenAll), multiple exceptions may be associated with a single task.
Target Environment
When you implement a TAP method, you can determine where asynchronous execution occurs. You may choose
to execute the workload on the thread pool, implement it by using asynchronous I/O (without being bound to a
thread for the majority of the operation’s execution), run it on a specific thread (such as the UI thread), or use any
number of potential contexts. A TAP method may even have nothing to execute, and may just return a Task that
represents the occurrence of a condition elsewhere in the system (for example, a task that represents data arriving
at a queued data structure).The caller of the TAP method may block waiting for the TAP method to complete by
synchronously waiting on the resulting task, or may run additional (continuation) code when the asynchronous
operation completes. The creator of the continuation code has control over where that code executes. You may
create the continuation code either explicitly, through methods on the Task class (for example, ContinueWith) or
implicitly, by using language support built on top of continuations (for example, await in C#, Await in Visual
Basic, AwaitValue in F#).
Task Status
The Task class provides a life cycle for asynchronous operations, and that cycle is represented by the TaskStatus
enumeration. To support corner cases of types that derive from Task and Task<TResult>, and to support the
separation of construction from scheduling, the Task class exposes a Start method. Tasks that are created by the
public Task constructors are referred to as cold tasks, because they begin their life cycle in the non-scheduled
Created state and are scheduled only when Start is called on these instances.
All other tasks begin their life cycle in a hot state, which means that the asynchronous operations they represent
have already been initiated and their task status is an enumeration value other than
System.Threading.Tasks.TaskStatus.Created. All tasks that are returned from TAP methods must be activated. If a
TAP method internally uses a task’s constructor to instantiate the task to be returned, the TAP method
must call Start on the Task object before returning it. Consumers of a TAP method may safely assume that
the returned task is active and should not try to call Start on any Task that is returned from a TAP method. Calling
Start on an active task results in an InvalidOperationException exception.
Cancellation (Optional)
In TAP, cancellation is optional for both asynchronous method implementers and asynchronous method
consumers. If an operation allows cancellation, it exposes an overload of the asynchronous method that accepts a
cancellation token (CancellationToken instance). By convention, the parameter is named cancellationToken .
public Task ReadAsync(byte [] buffer, int offset, int count,
CancellationToken cancellationToken)
The asynchronous operation monitors this token for cancellation requests. If it receives a cancellation request, it
may choose to honor that request and cancel the operation. If the cancellation request results in work being ended
prematurely, the TAP method returns a task that ends in the Canceled state; there is no available result and no
exception is thrown. The Canceled state is considered to be a final (completed) state for a task, along with the
Faulted and RanToCompletion states. Therefore, if a task is in the Canceled state, its IsCompleted property returns
true . When a task completes in the Canceled state, any continuations registered with the task are scheduled or
executed, unless a continuation option such as NotOnCanceled was specified to opt out of continuation. Any code
that is asynchronously waiting for a canceled task through use of language features continues to run but receives
an OperationCanceledException or an exception derived from it. Code that is blocked synchronously waiting on
the task through methods such as Wait and WaitAll also continue to run with an exception.
If a cancellation token has requested cancellation before the TAP method that accepts that token is called, the TAP
method should return a Canceled task. However, if cancellation is requested while the asynchronous operation is
running, the asynchronous operation need not accept the cancellation request. The returned task should end in the
Canceled state only if the operation ends as a result of the cancellation request. If cancellation is requested but a
result or an exception is still produced, the task should end in the RanToCompletion or Faulted state. For
asynchronous methods used by a developer who wants cancellation first and foremost, you don't have to provide
an overload that doesn’t accept a cancellation token. For methods that cannot be canceled, do not provide
overloads that accept a cancellation token; this helps indicate to the caller whether the target method is actually
cancelable. Consumer code that does not desire cancellation may call a method that accepts a CancellationToken
and provide None as the argument value. None is functionally equivalent to the default CancellationToken.
If a FindFilesAsync method returns a list of all files that meet a particular search pattern, the progress callback
could provide an estimate of the percentage of work completed as well as the current set of partial results. It could
do this either with a tuple:
In the latter case, the special data type is usually suffixed with ProgressInfo .
If TAP implementations provide overloads that accept a progress parameter, they must allow the argument to be
null , in which case no progress will be reported. TAP implementations should report the progress to the
Progress<T> object synchronously, which enables the asynchronous method to quickly provide progress, and
allow the consumer of the progress to determine how and where best to handle the information. For example, the
progress instance could choose to marshal callbacks and raise events on a captured synchronization context.
IProgress<T> Implementations
The .NET Framework 4.5 provides a single IProgress<T> implementation: Progress<T>. The Progress<T> class is
declared as follows:
An instance of Progress<T> exposes a ProgressChanged event, which is raised every time the asynchronous
operation reports a progress update. The ProgressChanged event is raised on the SynchronizationContext object
that was captured when the Progress<T> instance was instantiated. If no synchronization context was available, a
default context that targets the thread pool is used. Handlers may be registered with this event. A single handler
may also be provided to the Progress<T> constructor for convenience, and behaves just like an event handler for
the ProgressChanged event. Progress updates are raised asynchronously to avoid delaying the asynchronous
operation while event handlers are executing. Another IProgress<T> implementation could choose to apply
different semantics.
However, many TAP implementations provide neither cancellation or progress capabilities, so they require a single
method:
If a TAP implementation supports either cancellation or progress but not both, it may provide two overloads:
// … or …
' … or …
If a TAP implementation supports both cancellation and progress, it may expose all four overloads. However, it
may provide only the following two:
To compensate for the two missing intermediate combinations, developers may pass None or a default
CancellationToken for the cancellationToken parameter and null for the progress parameter.
If you expect every usage of the TAP method to support cancellation or progress, you may omit the overloads that
don’t accept the relevant parameter.
If you decide to expose multiple overloads to make cancellation or progress optional, the overloads that don’t
support cancellation or progress should behave as if they passed None for cancellation or null for progress to
the overload that does support these.
Related Topics
TITLE DESCRIPTION
Asynchronous Programming Patterns Introduces the three patterns for performing asynchronous
operations: the Task-based Asynchronous Pattern (TAP), the
Asynchronous Programming Model (APM), and the Event-
based Asynchronous Pattern (EAP).
Implementing the Task-based Asynchronous Pattern Describes how to implement the Task-based Asynchronous
Pattern (TAP) in three ways: by using the C# and Visual Basic
compilers in Visual Studio, manually, or through a
combination of the compiler and manual methods.
Consuming the Task-based Asynchronous Pattern Describes how you can use tasks and callbacks to achieve
waiting without blocking.
Interop with Other Asynchronous Patterns and Types Describes how to use the Task-based Asynchronous Pattern
(TAP) to implement the Asynchronous Programming Model
(APM) and Event-based Asynchronous Pattern (EAP).
Implementing the Task-based Asynchronous Pattern
9/6/2017 • 9 min to read • Edit Online
You can implement the Task-based Asynchronous Pattern (TAP) in three ways: by using the C# and Visual Basic
compilers in Visual Studio, manually, or through a combination of the compiler and manual methods. The
following sections discuss each method in detail. You can use the TAP pattern to implement both compute-bound
and I/O-bound asynchronous operations. The Workloads section discusses each type of operation.
public static Task<int> ReadTask(this Stream stream, byte[] buffer, int offset, int count, object state)
{
var tcs = new TaskCompletionSource<int>();
stream.BeginRead(buffer, offset, count, ar =>
{
try { tcs.SetResult(stream.EndRead(ar)); }
catch (Exception exc) { tcs.SetException(exc); }
}, state);
return tcs.Task;
}
<Extension()>
Public Function ReadTask(stream As Stream, buffer() As Byte,
offset As Integer, count As Integer,
state As Object) As Task(Of Integer)
Dim tcs As New TaskCompletionSource(Of Integer)()
stream.BeginRead(buffer, offset, count, Sub(ar)
Try
tcs.SetResult(stream.EndRead(ar))
Catch exc As Exception
tcs.SetException(exc)
End Try
End Sub, state)
Return tcs.Task
End Function
Hybrid approach
You may find it useful to implement the TAP pattern manually but to delegate the core logic for the
implementation to the compiler. For example, you may want to use the hybrid approach when you want to verify
arguments outside a compiler-generated asynchronous method so that exceptions can escape to the method’s
direct caller rather than being exposed through the System.Threading.Tasks.Task object:
return value;
}
Return MethodAsyncInternal(input)
End Function
return value
End Function
Another case where such delegation is useful is when you're implementing fast-path optimization and want to
return a cached task.
Workloads
You may implement both compute-bound and I/O-bound asynchronous operations as TAP methods. However,
when TAP methods are exposed publicly from a library, they should be provided only for workloads that involve
I/O-bound operations (they may also involve computation, but should not be purely computational). If a method is
purely compute-bound, it should be exposed only as a synchronous implementation. The code that consumes it
may then choose whether to wrap an invocation of that synchronous method into a task to offload the work to
another thread or to achieve parallelism. And if a method is IO-bound, it should be exposed only as an
asynchronous implementation.
Compute -bound tasks
The System.Threading.Tasks.Task class is ideally suited for representing computationally intensive operations. By
default, it takes advantage of special support within the ThreadPool class to provide efficient execution, and it also
provides significant control over when, where, and how asynchronous computations execute.
You can generate compute-bound tasks in the following ways:
In the .NET Framework 4, use the System.Threading.Tasks.TaskFactory.StartNew method, which accepts a
delegate (typically an Action<T> or a Func<TResult>) to be executed asynchronously. If you provide an
Action<T> delegate, the method returns a System.Threading.Tasks.Task object that represents the
asynchronous execution of that delegate. If you provide a Func<TResult> delegate, the method returns a
System.Threading.Tasks.Task<TResult> object. Overloads of the StartNew method accept a cancellation
token (CancellationToken), task creation options (TaskCreationOptions), and a task scheduler
(TaskScheduler), all of which provide fine-grained control over the scheduling and execution of the task. A
factory instance that targets the current task scheduler is available as a static property (Factory) of the Task
class; for example: Task.Factory.StartNew(…) .
In the .NET Framework 4.5 and later versions (including .NET Core and .NET Standard), use the static
System.Threading.Tasks.Task.Run method as a shortcut to System.Threading.Tasks.TaskFactory.StartNew.
You may use Run to easily launch a compute-bound task that targets the thread pool. In the .NET
Framework 4.5 and later versions, this is the preferred mechanism for launching a compute-bound task. Use
StartNew directly only when you want more fine-grained control over the task.
Use the constructors of the Task type or the Start method if you want to generate and schedule the task
separately. Public methods must only return tasks that have already been started.
Use the overloads of the System.Threading.Tasks.Task.ContinueWith method. This method creates a new
task that is scheduled when another task completes. Some of the ContinueWith overloads accept a
cancellation token, continuation options, and a task scheduler for better control over the scheduling and
execution of the continuation task.
Use the System.Threading.Tasks.TaskFactory.ContinueWhenAll and
System.Threading.Tasks.TaskFactory.ContinueWhenAny methods. These methods create a new task that is
scheduled when all or any of a supplied set of tasks completes. These methods also provide overloads to
control the scheduling and execution of these tasks.
In compute-bound tasks, the system can prevent the execution of a scheduled task if it receives a cancellation
request before it starts running the task. As such, if you provide a cancellation token (CancellationToken object),
you can pass that token to the asynchronous code that monitors the token. You can also provide the token to one
of the previously mentioned methods such as StartNew or Run so that the Task runtime may also monitor the
token.
For example, consider an asynchronous method that renders an image. The body of the task can poll the
cancellation token so that the code may exit early if a cancellation request arrives during rendering. In addition, if
the cancellation request arrives before rendering starts, you'll want to prevent the rendering operation:
internal Task<Bitmap> RenderAsync(
ImageData data, CancellationToken cancellationToken)
{
return Task.Run(() =>
{
var bmp = new Bitmap(data.Width, data.Height);
for(int y=0; y<data.Height; y++)
{
cancellationToken.ThrowIfCancellationRequested();
for(int x=0; x<data.Width; x++)
{
// render pixel [x,y] into bmp
}
}
return bmp;
}, cancellationToken);
}
Compute-bound tasks end in a Canceled state if at least one of the following conditions is true:
A cancellation request arrives through the CancellationToken object, which is provided as an argument to
the creation method (for example, StartNew or Run ) before the task transitions to the Running state.
An OperationCanceledException exception goes unhandled within the body of such a task, that exception
contains the same CancellationToken that is passed to the task, and that token shows that cancellation is
requested.
If another exception goes unhandled within the body of the task, the task ends in the Faulted state, and any
attempts to wait on the task or access its result causes an exception to be thrown.
I/O -bound tasks
To create a task that should not be directly backed by a thread for the entirety of its execution, use the
TaskCompletionSource<TResult> type. This type exposes a Task property that returns an associated
Task<TResult> instance. The life cycle of this task is controlled by TaskCompletionSource<TResult> methods such
as SetResult, SetException, SetCanceled, and their TrySet variants.
Let's say that you want to create a task that will complete after a specified period of time. For example, you may
want to delay an activity in the user interface. The System.Threading.Timer class already provides the ability to
asynchronously invoke a delegate after a specified period of time, and by using TaskCompletionSource<TResult>
you can put a Task<TResult> front on the timer, for example:
public static Task<DateTimeOffset> Delay(int millisecondsTimeout)
{
TaskCompletionSource<DateTimeOffset> tcs = null;
Timer timer = null;
Starting with the .NET Framework 4.5, the System.Threading.Tasks.Task.Delay method is provided for this purpose,
and you can use it inside another asynchronous method, for example, to implement an asynchronous polling loop:
This example also demonstrates how a single cancellation token may be threaded through multiple asynchronous
operations. For more information, see the cancellation usage section in Consuming the Task-based Asynchronous
Pattern.
See also
Task-based Asynchronous Pattern (TAP)
Consuming the Task-based Asynchronous Pattern
Interop with Other Asynchronous Patterns and Types
Consuming the Task-based Asynchronous Pattern
7/29/2017 • 22 min to read • Edit Online
When you use the Task-based Asynchronous Pattern (TAP) to work with asynchronous operations, you can use
callbacks to achieve waiting without blocking. For tasks, this is achieved through methods such as
System.Threading.Tasks.Task.ContinueWith. Language-based asynchronous support hides callbacks by allowing
asynchronous operations to be awaited within normal control flow, and compiler-generated code provides this
same API-level support.
Task.Run(async delegate
{
for(int i=0; i<1000000; i++)
{
await Task.Yield(); // fork the continuation into a separate work item
...
}
});
You can also use the System.Threading.Tasks.Task.ConfigureAwait method for better control over suspension and
resumption in an asynchronous method. As mentioned previously, by default, the current context is captured at
the time an asynchronous method is suspended, and that captured context is used to invoke the asynchronous
method’s continuation upon resumption. In many cases, this is the exact behavior you want. In other cases, you
may not care about the continuation context, and you can achieve better performance by avoiding such posts back
to the original context. To enable this, use the System.Threading.Tasks.Task.ConfigureAwait method to inform the
await operation not to capture and resume on the context, but to continue execution wherever the asynchronous
operation that was being awaited completed:
await someTask.ConfigureAwait(continueOnCapturedContext:false);
To cancel multiple asynchronous invocations, you can pass the same token to all invocations:
Monitoring Progress
Some asynchronous methods expose progress through a progress interface passed into the asynchronous
method. For example, consider a function which asynchronously downloads a string of text, and along the way
raises progress updates that include the percentage of the download that has completed thus far. Such a method
could be consumed in a Windows Presentation Foundation (WPF) application as follows:
Task.WhenAll
Use the WhenAll method to asynchronously wait on multiple asynchronous operations that are represented as
tasks. The method has multiple overloads that support a set of non-generic tasks or a non-uniform set of generic
tasks (for example, asynchronously waiting for multiple void-returning operations, or asynchronously waiting for
multiple value-returning methods where each value may have a different type) and to support a uniform set of
generic tasks (such as asynchronously waiting for multiple TResult -returning methods).
Let's say you want to send email messages to several customers. You can overlap sending the messages so you're
not waiting for one message to complete before sending the next. You can also find out when the send operations
have completed and whether any errors have occurred:
In this case, if any asynchronous operation fails, all the exceptions will be consolidated in an AggregateException
exception, which is stored in the Task that is returned from the WhenAll method. However, only one of those
exceptions is propagated by the await keyword. If you want to examine all the exceptions, you can rewrite the
previous code as follows:
Let's consider an example of downloading multiple files from the web asynchronously. In this case, all the
asynchronous operations have homogeneous result types, and it's easy to access the results:
You can use the same exception-handling techniques we discussed in the previous void-returning scenario:
Task [] asyncOps =
(from url in urls select DownloadStringAsync(url)).ToArray();
try
{
string [] pages = await Task.WhenAll(asyncOps);
...
}
catch(Exception exc)
{
foreach(Task<string> faulted in asyncOps.Where(t => t.IsFaulted))
{
… // work with faulted and faulted.Exception
}
}
Task.WhenAny
You can use the WhenAny method to asynchronously wait for just one of multiple asynchronous operations
represented as tasks to complete. This method serves four primary use cases:
Redundancy: Performing an operation multiple times and selecting the one that completes first (for
example, contacting multiple stock quote web services that will produce a single result and selecting the
one that completes the fastest).
Interleaving: Launching multiple operations and waiting for all of them to complete, but processing them as
they complete.
Throttling: Allowing additional operations to begin as others complete. This is an extension of the
interleaving scenario.
Early bailout: For example, an operation represented by task t1 can be grouped in a WhenAny task with
another task t2, and you can wait on the WhenAny task. Task t2 could represent a time-out, or cancellation,
or some other signal that causes the WhenAny task to complete before t1 completes.
Redundancy
Consider a case where you want to make a decision about whether to buy a stock. There are several stock
recommendation web services that you trust, but depending on daily load, each service can end up being slow at
different times. You can use the WhenAny method to receive a notification when any operation completes:
Unlike WhenAll, which returns the unwrapped results of all tasks that completed successfully, WhenAny returns
the task that completed. If a task fails, it’s important to know that it failed, and if a task succeeds, it’s important to
know which task the return value is associated with. Therefore, you need to access the result of the returned task,
or further await it, as this example shows.
As with WhenAll, you have to be able to accommodate exceptions. Because you receive the completed task back,
you can await the returned task to have errors propagated, and try/catch them appropriately; for example:
Task<bool> [] recommendations = …;
while(recommendations.Count > 0)
{
Task<bool> recommendation = await Task.WhenAny(recommendations);
try
{
if (await recommendation) BuyStock(symbol);
break;
}
catch(WebException exc)
{
recommendations.Remove(recommendation);
}
}
Additionally, even if a first task completes successfully, subsequent tasks may fail. At this point, you have several
options for dealing with exceptions: You can wait until all the launched tasks have completed, in which case you
can use the WhenAll method, or you can decide that all exceptions are important and must be logged. For this,
you can use continuations to receive a notification when tasks have completed asynchronously:
foreach(Task recommendation in recommendations)
{
var ignored = recommendation.ContinueWith(
t => { if (t.IsFaulted) Log(t.Exception); });
}
or:
or even:
Interleaving
Consider a case where you're downloading images from the web and processing each image (for example, adding
the image to a UI control). You have to do the processing sequentially on the UI thread, but you want to download
the images as concurrently as possible. Also, you don’t want to hold up adding the images to the UI until they’re
all downloaded—you want to add them as they complete:
List<Task<Bitmap>> imageTasks =
(from imageUrl in urls select GetBitmapAsync(imageUrl)).ToList();
while(imageTasks.Count > 0)
{
try
{
Task<Bitmap> imageTask = await Task.WhenAny(imageTasks);
imageTasks.Remove(imageTask);
You can also apply interleaving to a scenario that involves computationally intensive processing on the
ThreadPool of the downloaded images; for example:
List<Task<Bitmap>> imageTasks =
(from imageUrl in urls select GetBitmapAsync(imageUrl)
.ContinueWith(t => ConvertImage(t.Result)).ToList();
while(imageTasks.Count > 0)
{
try
{
Task<Bitmap> imageTask = await Task.WhenAny(imageTasks);
imageTasks.Remove(imageTask);
Throttling
Consider the interleaving example, except that the user is downloading so many images that the downloads have
to be throttled; for example, you want only a specific number of downloads to happen concurrently. To achieve
this, you can start a subset of the asynchronous operations. As operations complete, you can start additional
operations to take their place:
const int CONCURRENCY_LEVEL = 15;
Uri [] urls = …;
int nextIndex = 0;
var imageTasks = new List<Task<Bitmap>>();
while(nextIndex < CONCURRENCY_LEVEL && nextIndex < urls.Length)
{
imageTasks.Add(GetBitmapAsync(urls[nextIndex]));
nextIndex++;
}
while(imageTasks.Count > 0)
{
try
{
Task<Bitmap> imageTask = await Task.WhenAny(imageTasks);
imageTasks.Remove(imageTask);
Early Bailout
Consider that you're waiting asynchronously for an operation to complete while simultaneously responding to a
user’s cancellation request (for example, the user clicked a cancel button). The following code illustrates this
scenario:
private CancellationTokenSource m_cts;
This implementation re-enables the user interface as soon as you decide to bail out, but doesn't cancel the
underlying asynchronous operations. Another alternative would be to cancel the pending operations when you
decide to bail out, but not reestablish the user interface until the operations actually complete, potentially due to
ending early due to the cancellation request:
btnRun.Enabled = false;
try
{
Task<Bitmap> imageDownload = GetBitmapAsync(txtUrl.Text, m_cts.Token);
await UntilCompletionOrCancellation(imageDownload, m_cts.Token);
Bitmap image = await imageDownload;
panel.AddImage(image);
}
catch(OperationCanceledException) {}
finally { btnRun.Enabled = true; }
}
Another example of early bailout involves using the WhenAny method in conjunction with the Delay method, as
discussed in the next section.
Task.Delay
You can use the System.Threading.Tasks.Task.Delay method to introduce pauses into an asynchronous method’s
execution. This is useful for many kinds of functionality, including building polling loops and delaying the handling
of user input for a predetermined period of time. The System.Threading.Tasks.Task.Delay method can also be
useful in combination with System.Threading.Tasks.Task.WhenAny for implementing time-outs on awaits.
If a task that’s part of a larger asynchronous operation (for example, an ASP.NET web service) takes too long to
complete, the overall operation could suffer, especially if it fails to ever complete. For this reason, it’s important to
be able to time out when waiting on an asynchronous operation. The synchronous
System.Threading.Tasks.Task.Wait, System.Threading.Tasks.Task.WaitAll, and
System.Threading.Tasks.Task.WaitAny methods accept time-out values, but the corresponding
System.Threading.Tasks.TaskFactory.ContinueWhenAll/System.Threading.Tasks.Task.WhenAny and the previously
mentioned System.Threading.Tasks.Task.WhenAll/System.Threading.Tasks.Task.WhenAny methods do not.
Instead, you can use System.Threading.Tasks.Task.Delay and System.Threading.Tasks.Task.WhenAny in
combination to implement a time-out.
For example, in your UI application, let's say that you want to download an image and disable the UI while the
image is downloading. However, if the download takes too long, you want to re-enable the UI and discard the
download:
You can build an almost identical helper method for asynchronous operations that are implemented with TAP and
thus return tasks:
You can then use this combinator to encode retries into the application’s logic; for example:
// Download the URL, trying up to three times in case of failure
string pageContents = await RetryOnFault(
() => DownloadStringAsync(url), 3);
You could extend the RetryOnFault function further. For example, the function could accept another Func<Task>
that will be invoked between retries to determine when to try the operation again; for example:
You could then use the function as follows to wait for a second before retrying the operation:
NeedOnlyOne
Sometimes, you can take advantage of redundancy to improve an operation’s latency and chances for success.
Consider multiple web services that provide stock quotes, but at various times of the day, each service may
provide different levels of quality and response times. To deal with these fluctuations, you may issue requests to
all the web services, and as soon as you get a response from one, cancel the remaining requests. You can
implement a helper function to make it easier to implement this common pattern of launching multiple
operations, waiting for any, and then canceling the rest. The NeedOnlyOne function in the following example
illustrates this scenario:
Interleaved Operations
There is a potential performance problem with using the WhenAny method to support an interleaving scenario
when you're working with very large sets of tasks. Every call to WhenAny results in a continuation being
registered with each task. For N number of tasks, this results in O(N2) continuations created over the lifetime of
the interleaving operation. If you're working with a large set of tasks, you can use a combinator ( Interleaved in
the following example) to address the performance issue:
You can then use the combinator to process the results of tasks as they complete; for example:
WhenAllOrFirstException
In certain scatter/gather scenarios, you might want to wait for all tasks in a set, unless one of them faults, in which
case you want to stop waiting as soon as the exception occurs. You can accomplish that with a combinator
method such as WhenAllOrFirstException in the following example:
public static Task<T[]> WhenAllOrFirstException<T>(IEnumerable<Task<T>> tasks)
{
var inputs = tasks.ToList();
var ce = new CountdownEvent(inputs.Count);
var tcs = new TaskCompletionSource<T[]>();
The AsyncCache<TKey,TValue> class accepts as a delegate to its constructor a function that takes a TKey and
returns a Task<TResult>. Any previously accessed values from the cache are stored in the internal dictionary, and
the AsyncCache ensures that only one task is generated per key, even if the cache is accessed concurrently.
For example, you can build a cache for downloaded web pages:
private AsyncCache<string,string> m_webPages =
new AsyncCache<string,string>(DownloadStringAsync);
You can then use this cache in asynchronous methods whenever you need the contents of a web page. The
AsyncCache class ensures that you’re downloading as few pages as possible, and caches the results.
AsyncProducerConsumerCollection
You can also use tasks to build data structures for coordinating asynchronous activities. Consider one of the
classic parallel design patterns: producer/consumer. In this pattern, producers generate data that is consumed by
consumers, and the producers and consumers may run in parallel. For example, the consumer processes item 1,
which was previously generated by a producer who is now producing item 2. For the producer/consumer pattern,
you invariably need some data structure to store the work created by producers so that the consumers may be
notified of new data and find it when available.
Here’s a simple data structure built on top of tasks that enables asynchronous methods to be used as producers
and consumers:
public class AsyncProducerConsumerCollection<T>
{
private readonly Queue<T> m_collection = new Queue<T>();
private readonly Queue<TaskCompletionSource<T>> m_waiting =
new Queue<TaskCompletionSource<T>>();
With that data structure in place, you can write code such as the following:
The System.Threading.Tasks.Dataflow namespace includes the BufferBlock<T> type, which you can use in a
similar manner, but without having to build a custom collection type:
private static BufferBlock<int> m_data = …;
…
private static async Task ConsumerAsync()
{
while(true)
{
int nextItem = await m_data.ReceiveAsync();
ProcessNextItem(nextItem);
}
}
…
private static void Produce(int data)
{
m_data.Post(data);
}
NOTE
The System.Threading.Tasks.Dataflow namespace is available in the .NET Framework 4.5 through NuGet. To install the
assembly that contains the System.Threading.Tasks.Dataflow namespace, open your project in Visual Studio 2012, choose
Manage NuGet Packages from the Project menu, and search online for the Microsoft.Tpl.Dataflow package.
See Also
Task-based Asynchronous Pattern (TAP)
Implementing the Task-based Asynchronous Pattern
Interop with Other Asynchronous Patterns and Types
Interop with Other Asynchronous Patterns and Types
7/29/2017 • 6 min to read • Edit Online
The .NET Framework 1.0 introduced the IAsyncResult pattern, otherwise known as the Asynchronous
Programming Model (APM), or the Begin/End pattern. The .NET Framework 2.0 added the Event-based
Asynchronous Pattern (EAP). Starting with the .NET Framework 4, the Task-based Asynchronous Pattern (TAP)
supersedes both APM and EAP, but provides the ability to easily build migration routines from the earlier patterns.
In this topic:
Tasks and APM (from APM to TAP or from TAP to APM)
Tasks and EAP
Tasks and wait handles (from wait handles to TAP or from TAP to wait handles)
return Task<int>.Factory.FromAsync(stream.BeginRead,
stream.EndRead, buffer,
offset, count, null);
}
<Extension()>
Public Function ReadAsync(strm As Stream,
buffer As Byte(), offset As Integer,
count As Integer) As Task(Of Integer)
If strm Is Nothing Then
Throw New ArgumentNullException("stream")
End If
if (callback != null)
callback(tcs.Task);
}, TaskScheduler.Default);
return tcs.Task;
}
<Extension()>
Public Function AsApm(Of T)(task As Task(Of T),
callback As AsyncCallback,
state As Object) As IAsyncResult
If task Is Nothing Then
Throw New ArgumentNullException("task")
End If
Now, consider a case where you have the following TAP implementation:
<Extension()>
Public Function WaitOneAsync(waitHandle As WaitHandle) As Task
If waitHandle Is Nothing Then
Throw New ArgumentNullException("waitHandle")
End If
With this method, you can use existing WaitHandle implementations in asynchronous methods. For example, if
you want to throttle the number of asynchronous operations that are executing at any particular time, you can
utilize a semaphore (a System.Threading.SemaphoreSlim object). You can throttle to N the number of operations
that run concurrently by initializing the semaphore’s count to N, waiting on the semaphore any time you want to
perform an operation, and releasing the semaphore when you’re done with an operation:
static int N = 3;
Shared N As Integer = 3
You can also build an asynchronous semaphore that does not rely on wait handles and instead works completely
with tasks. To do this, you can use techniques such as those discussed in Consuming the Task-based
Asynchronous Pattern for building data structures on top of Task.
From TAP to Wait Handles
As previously mentioned, the Task class implements IAsyncResult, and that implementation exposes an
IAsyncResult.AsyncWaitHandle property that returns a wait handle that will be set when the Task completes. You
can get a WaitHandle for a Task as follows:
WaitHandle wh = ((IAsyncResult)task).AsyncWaitHandle;
See Also
Task-based Asynchronous Pattern (TAP)
Implementing the Task-based Asynchronous Pattern
Consuming the Task-based Asynchronous Pattern
Event-based Asynchronous Pattern (EAP)
7/29/2017 • 1 min to read • Edit Online
There are a number of ways to expose asynchronous features to client code. The Event-based Asynchronous
Pattern prescribes one way for classes to present asynchronous behavior.
NOTE
Starting with the .NET Framework 4, the Task Parallel Library provides a new model for asynchronous and parallel
programming. For more information, see Parallel Programming.
In This Section
Event-based Asynchronous Pattern Overview
Describes how the Event-based Asynchronous Pattern makes available the advantages of multithreaded
applications while hiding many of the complex issues inherent in multithreaded design.
Implementing the Event-based Asynchronous Pattern
Describes the standardized way to package a class that has asynchronous features.
Best Practices for Implementing the Event-based Asynchronous Pattern
Describes the requirements for exposing asynchronous features according to the Event-based Asynchronous
Pattern.
Deciding When to Implement the Event-based Asynchronous Pattern
Describes how to determine when you should choose to implement the Event-based Asynchronous Pattern
instead of the IAsyncResult pattern.
Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern
Illustrates how to create a component that implements the Event-based Asynchronous Pattern. It is implemented
using helper classes from the System.ComponentModel namespace, which ensures that the component works
correctly under any application model.
How to: Use Components That Support the Event-based Asynchronous Pattern
Describes how to use a component that supports the Event-based Asynchronous Pattern.
Reference
AsyncOperation
Describes the AsyncOperation class and has links to all its members.
AsyncOperationManager
Describes the AsyncOperationManager class and has links to all its members.
BackgroundWorker
Describes the BackgroundWorker component and has links to all its members.
Related Sections
Task Parallel Library (TPL)
Describes a programming model for asynchronous and parallel operations.
Threading
Describes multithreading features in the .NET Framework.
Threading
Describes multithreading features in the C# and Visual Basic languages.
See Also
Managed Threading Best Practices
Events
Multithreading in Components
Asynchronous Programming Design Patterns
Multithreaded Programming with the Event-based
Asynchronous Pattern
7/29/2017 • 1 min to read • Edit Online
There are a number of ways to expose asynchronous features to client code. The Event-based Asynchronous
Pattern prescribes the recommended way for classes to present asynchronous behavior.
In This Section
Event-based Asynchronous Pattern Overview
Describes how the Event-based Asynchronous Pattern makes available the advantages of multithreaded
applications while hiding many of the complex issues inherent in multithreaded design.
Implementing the Event-based Asynchronous Pattern
Describes the standardized way to package a class that has asynchronous features.
Best Practices for Implementing the Event-based Asynchronous Pattern
Describes the requirements for exposing asynchronous features according to the Event-based Asynchronous
Pattern.
Deciding When to Implement the Event-based Asynchronous Pattern
Describes how to determine when you should choose to implement the Event-based Asynchronous Pattern
instead of the IAsyncResult pattern.
Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern
Illustrates how to create a component that implements the Event-based Asynchronous Pattern. It is implemented
using helper classes from the System.ComponentModel namespace, which ensures that the component works
correctly under any application model.
How to: Use Components That Support the Event-based Asynchronous Pattern
Describes how to use a component that supports the Event-based Asynchronous Pattern.
Reference
AsyncOperation
Describes the AsyncOperation class and has links to all its members.
AsyncOperationManager
Describes the AsyncOperationManager class and has links to all its members.
BackgroundWorker
Describes the BackgroundWorker component and has links to all its members.
See Also
Managed Threading Best Practices
Events
Multithreading in Components
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
7/29/2017 • 6 min to read • Edit Online
Applications that perform many tasks simultaneously, yet remain responsive to user interaction, often require a
design that uses multiple threads. The System.Threading namespace provides all the tools necessary to create
high-performance multithreaded applications, but using these tools effectively requires significant experience
with multithreaded software engineering. For relatively simple multithreaded applications, the
BackgroundWorker component provides a straightforward solution. For more sophisticated asynchronous
applications, consider implementing a class that adheres to the Event-based Asynchronous Pattern.
The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while
hiding many of the complex issues inherent in multithreaded design. Using a class that supports this pattern can
allow you to:
Perform time-consuming tasks, such as downloads and database operations, "in the background," without
interrupting your application.
Execute multiple operations simultaneously, receiving notifications when each completes.
Wait for resources to become available without stopping ("hanging") your application.
Communicate with pending asynchronous operations using the familiar events-and-delegates model. For
more information on using event handlers and delegates, see Events.
A class that supports the Event-based Asynchronous Pattern will have one or more methods named
MethodName Async . These methods may mirror synchronous versions, which perform the same operation on
the current thread. The class may also have a MethodName Completed event and it may have a MethodName
AsyncCancel (or simply CancelAsync ) method.
PictureBox is a typical component that supports the Event-based Asynchronous Pattern. You can download an
image synchronously by calling its Load method, but if the image is large, or if the network connection is slow,
your application will stop ("hang") until the download operation is completed and the call to Load returns.
If you want your application to keep running while the image is loading, you can call the LoadAsync method and
handle the LoadCompleted event, just as you would handle any other event. When you call the LoadAsync
method, your application will continue to run while the download proceeds on a separate thread ("in the
background"). Your event handler will be called when the image-loading operation is complete, and your event
handler can examine the AsyncCompletedEventArgs parameter to determine if the download completed
successfully.
The Event-based Asynchronous Pattern requires that an asynchronous operation can be canceled, and the
PictureBox control supports this requirement with its CancelAsync method. Calling CancelAsync submits a
request to stop the pending download, and when the task is canceled, the LoadCompleted event is raised.
Cau t i on
It is possible that the download will finish just as the CancelAsync request is made, so Cancelled may not reflect
the request to cancel. This is called a race condition and is a common issue in multithreaded programming. For
more information on issues in multithreaded programming, see Managed Threading Best Practices.
// Asynchronous methods.
public void Method1Async(string param);
public void Method1Async(string param, object userState);
public event Method1CompletedEventHandler Method1Completed;
The fictitious AsyncExample class has two methods, both of which support synchronous and asynchronous
invocations. The synchronous overloads behave like any method call and execute the operation on the calling
thread; if the operation is time-consuming, there may be a noticeable delay before the call returns. The
asynchronous overloads will start the operation on another thread and then return immediately, allowing the
calling thread to continue while the operation executes "in the background."
Asynchronous Method Overloads
There are potentially two overloads for the asynchronous operations: single-invocation and multiple-invocation.
You can distinguish these two forms by their method signatures: the multiple-invocation form has an extra
parameter called userState . This form makes it possible for your code to call
Method1Async(string param, object userState) multiple times without waiting for any pending asynchronous
operations to finish. If, on the other hand, you try to call Method1Async(string param) before a previous invocation
has completed, the method raises an InvalidOperationException.
The userState parameter for the multiple-invocation overloads allows you to distinguish among asynchronous
operations. You provide a unique value (for example, a GUID or hash code) for each call to
Method1Async(string param, object userState) , and when each operation is completed, your event handler can
determine which instance of the operation raised the completion event.
Tracking Pending Operations
If you use the multiple-invocation overloads, your code will need to keep track of the userState objects (task
IDs) for pending tasks. For each call to Method1Async(string param, object userState) , you will typically generate
a new, unique userState object and add it to a collection. When the task corresponding to this userState object
raises the completion event, your completion method implementation will examine
System.ComponentModel.AsyncCompletedEventArgs.UserState and remove it from your collection. Used this
way, the userState parameter takes the role of a task ID.
NOTE
You must be careful to provide a unique value for userState in your calls to multiple-invocation overloads. Non-unique
task IDs will cause the asynchronous class throw an ArgumentException.
See Also
ProgressChangedEventArgs
BackgroundWorker
AsyncCompletedEventArgs
How to: Use Components That Support the Event-based Asynchronous Pattern
How to: Run an Operation in the Background
How to: Implement a Form That Uses a Background Operation
Multithreaded Programming with the Event-based Asynchronous Pattern
Best Practices for Implementing the Event-based Asynchronous Pattern
Deciding When to Implement the Event-based Asynchronous Pattern
Implementing the Event-based Asynchronous Pattern
7/29/2017 • 8 min to read • Edit Online
If you are writing a class with some operations that may incur noticeable delays, consider giving it asynchronous
functionality by implementing Event-based Asynchronous Pattern Overview.
The Event-based Asynchronous Pattern provides a standardized way to package a class that has asynchronous
features. If implemented with helper classes like AsyncOperationManager, your class will work correctly under any
application model, including ASP.NET, Console applications, and Windows Forms applications.
For an example that implements the Event-based Asynchronous Pattern, see How to: Implement a Component
That Supports the Event-based Asynchronous Pattern.
For simple asynchronous operations, you may find the BackgroundWorker component suitable. For more
information about BackgroundWorker, see How to: Run an Operation in the Background.
The following list describes the features of the Event-based Asynchronous Pattern discussed in this topic.
Opportunities for Implementing the Event-based Asynchronous Pattern
Naming Asynchronous Methods
Optionally Support Cancellation
Optionally Support the IsBusy Property
Optionally Provide Support for Progress Reporting
Optionally Provide Support for Returning Incremental Results
Handling Out and Ref Parameters in Methods
2. Define the following delegate and AsyncCompletedEventArgs. These will likely be defined outside of the
class itself, but in the same namespace.
Ensure that the MethodName CompletedEventArgs class exposes its members as read-only properties,
and not fields, as fields prevent data binding.
Do not define any AsyncCompletedEventArgs-derived classes for methods that do not produce
results. Simply use an instance of AsyncCompletedEventArgs itself.
NOTE
It is perfectly acceptable, when feasible and appropriate, to reuse delegate and AsyncCompletedEventArgs
types. In this case, the naming will not be as consistent with the method name, since a given delegate and
AsyncCompletedEventArgs won't be tied to a single method.
C#
MULTIPLE SIMULTANEOUS OPERATIONS
SUPPORTED ONLY ONE OPERATION AT A TIME
If you define the CancelAsync(object userState) method, clients must be careful when choosing their state values
to make them capable of distinguishing among all asynchronous methods invoked on the object, and not just
between all invocations of a single asynchronous method.
The decision to name the single-async-operation version MethodName AsyncCancel is based on being able to
more easily discover the method in a design environment like Visual Studio's IntelliSense. This groups the related
members and distinguishes them from other members that have nothing to do with asynchronous functionality. If
you expect that there may be additional asynchronous operations added in subsequent versions, it is better to
define CancelAsync .
Do not define multiple methods from the table above in the same class. That will not make sense, or it will clutter
the class interface with a proliferation of methods.
These methods typically will return immediately, and the operation may or may not actually cancel. In the event
handler for the MethodName Completed event, the MethodName CompletedEventArgs object contains a Cancelled
field, which clients can use to determine whether the cancellation occurred.
Abide by the cancellation semantics described in Best Practices for Implementing the Event-based Asynchronous
Pattern.
Raise this MethodName ProgressChanged event when there is an incremental result to report.
This solution applies specifically to a single-async-operation class because there is no problem with the same
event occurring to return incremental results on "all operations", as the MethodName ProgressChanged event does.
Multiple -operation Class with Homogeneous Incremental Results
In this case, your class supports multiple asynchronous methods, each capable of returning incremental results,
and these incremental results all have the same type of data.
Follow the model described above for single-operation classes, as the same EventArgs structure will work for all
incremental results. Define a ProgressChanged event instead of a MethodName ProgressChanged event, since it
applies to multiple asynchronous methods.
Multiple -operation Class with Heterogeneous Incremental Results
If your class supports multiple asynchronous methods, each returning a different type of data, you should:
Separate your incremental result reporting from your progress reporting.
Define a separate MethodName ProgressChanged event with appropriate EventArgs for each asynchronous
method to handle that method's incremental result data.
Invoke that event handler on the appropriate thread as described in Best Practices for Implementing the Event-
based Asynchronous Pattern.
Public Function MethodName(ByVal arg1 As String, ByRef arg2 As String, ByRef arg3 As String) As Integer
public int MethodName(string arg1, ref string arg2, out string arg3);
Your asynchronous method and its AsyncCompletedEventArgs class would look like this:
See Also
ProgressChangedEventArgs
AsyncCompletedEventArgs
How to: Implement a Component That Supports the Event-based Asynchronous Pattern
How to: Run an Operation in the Background
How to: Implement a Form That Uses a Background Operation
Deciding When to Implement the Event-based Asynchronous Pattern
Multithreaded Programming with the Event-based Asynchronous Pattern
Best Practices for Implementing the Event-based Asynchronous Pattern
Best Practices for Implementing the Event-based
Asynchronous Pattern
7/29/2017 • 8 min to read • Edit Online
The Event-based Asynchronous Pattern provides you with an effective way to expose asynchronous behavior in
classes, with familiar event and delegate semantics. To implement Event-based Asynchronous Pattern, you need
to follow some specific behavioral requirements. The following sections describe requirements and guidelines
you should consider when you implement a class that follows the Event-based Asynchronous Pattern.
For an overview, see Implementing the Event-based Asynchronous Pattern.
Ensure that the EventArgs class is specific to the return values of the MethodName method. When you use
the EventArgs class, you should never require developers to cast the result.
The following code example shows good and bad implementation of this design requirement respectively.
// Good design
private void Form1_MethodNameCompleted(object sender, xxxCompletedEventArgs e)
{
DemoType result = e.Result;
}
// Bad design
private void Form1_MethodNameCompleted(object sender, MethodNameCompletedEventArgs e)
{
DemoType result = (DemoType)(e.Result);
}
Do not define an EventArgs class for returning methods that return void . Instead, use an instance of the
AsyncCompletedEventArgs class.
Ensure that you always raise the MethodName Completed event. This event should be raised on successful
completion, on an error, or on cancellation. Applications should never encounter a situation where they
remain idle and completion never occurs.
Ensure that you catch any exceptions that occur in the asynchronous operation and assign the caught
exception to the Error property.
If there was an error completing the task, the results should not be accessible. When the Error property is
not null , ensure that accessing any property in the EventArgs structure raises an exception. Use the
RaiseExceptionIfNecessary method to perform this verification.
Model a time out as an error. When a time out occurs, raise the MethodName Completed event and assign
a TimeoutException to the Error property.
If your class supports multiple concurrent invocations, ensure that the MethodName Completed event
contains the appropriate userSuppliedState object.
Ensure that the MethodName Completed event is raised on the appropriate thread and at the appropriate
time in the application lifecycle. For more information, see the Threading and Contexts section.
Simultaneously Executing Operations
If your class supports multiple concurrent invocations, enable the developer to track each invocation
separately by defining the MethodName Async overload that takes an object-valued state parameter, or
task ID, called userSuppliedState . This parameter should always be the last parameter in the
MethodName Async method's signature.
If your class defines the MethodName Async overload that takes an object-valued state parameter, or task
ID, be sure to track the lifetime of the operation with that task ID, and be sure to provide it back into the
completion handler. There are helper classes available to assist. For more information on concurrency
management, see Walkthrough: Implementing a Component That Supports the Event-based
Asynchronous Pattern.
If your class defines the MethodName Async method without the state parameter, and it does not support
multiple concurrent invocations, ensure that any attempt to invoke MethodName Async before the prior
MethodName Async invocation has completed raises an InvalidOperationException.
In general, do not raise an exception if the MethodName Async method without the userSuppliedState
parameter is invoked multiple times so that there are multiple outstanding operations. You can raise an
exception when your class explicitly cannot handle that situation, but assume that developers can handle
these multiple indistinguishable callbacks
Accessing Results
If there was an error during execution of the asynchronous operation, the results should not be accessible.
Ensure that accessing any property in the AsyncCompletedEventArgs when Error is not null raises the
exception referenced by Error. The AsyncCompletedEventArgs class provides the
RaiseExceptionIfNecessary method for this purpose.
Ensure that any attempt to access the result raises an InvalidOperationException stating that the operation
was canceled. Use the System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary
method to perform this verification.
Progress Reporting
Support progress reporting, if possible. This enables developers to provide a better application user
experience when they use your class.
If you implement a ProgressChanged /MethodName ProgressChanged event, ensure that there are no such
events raised for a particular asynchronous operation after that operation's MethodName Completed event
has been raised.
If the standard ProgressChangedEventArgs is being populated, ensure that the ProgressPercentage can
always be interpreted as a percentage. The percentage does not need to be accurate, but it should
represent a percentage. If your progress reporting metric must be something other than a percentage,
derive a class from the ProgressChangedEventArgs class and leave ProgressPercentage at 0. Avoid using a
reporting metric other than a percentage.
Ensure that the ProgressChanged event is raised on the appropriate thread and at the appropriate time in
the application lifecycle. For more information, see the Threading and Contexts section.
IsBusy Implementation
Do not expose an IsBusy property if your class supports multiple concurrent invocations. For example,
XML Web service proxies do not expose an IsBusy property because they support multiple concurrent
invocations of asynchronous methods.
The IsBusy property should return true after the MethodName Async method has been called and
before the MethodName Completed event has been raised. Otherwise it should return false . The
BackgroundWorker and WebClient components are examples of classes that expose an IsBusy property.
Cancellation
Support cancellation, if possible. This enables developers to provide a better application user experience
when they use your class.
In the case of cancellation, set the Cancelled flag in the AsyncCompletedEventArgs object.
Ensure that any attempt to access the result raises an InvalidOperationException stating that the operation
was canceled. Use the System.ComponentModel.AsyncCompletedEventArgs.RaiseExceptionIfNecessary
method to perform this verification.
Ensure that calls to a cancellation method always return successfully, and never raise an exception. In
general, a client is not notified as to whether an operation is truly cancelable at any given time, and is not
notified as to whether a previously issued cancellation has succeeded. However, the application will always
be given notification when a cancellation succeeded, because the application takes part in the completion
status.
Raise the MethodName Completed event when the operation is canceled.
Errors and Exceptions
Catch any exceptions that occur in the asynchronous operation and set the value of the
System.ComponentModel.AsyncCompletedEventArgs.Error property to that exception.
Threading and Contexts
For correct operation of your class, it is critical that the client's event handlers are invoked on the proper thread
or context for the given application model, including ASP.NET and Windows Forms applications. Two important
helper classes are provided to ensure that your asynchronous class behaves correctly under any application
model: AsyncOperation and AsyncOperationManager.
AsyncOperationManager provides one method, CreateOperation, which returns an AsyncOperation. Your
MethodName Async method calls CreateOperation and your class uses the returned AsyncOperation to track the
lifetime of the asynchronous task.
To report progress, incremental results, and completion to the client, call the Post and OperationCompleted
methods on the AsyncOperation. AsyncOperation is responsible for marshaling calls to the client's event
handlers to the proper thread or context.
NOTE
You can circumvent these rules if you explicitly want to go against the policy of the application model, but still benefit from
the other advantages of using the Event-based Asynchronous Pattern. For example, you may want a class operating in
Windows Forms to be free threaded. You can create a free threaded class, as long as developers understand the implied
restrictions. Console applications do not synchronize the execution of Post calls. This can cause ProgressChanged events
to be raised out of order. If you wish to have serialized execution of Post calls, implement and install a
System.Threading.SynchronizationContext class.
For more information about using AsyncOperation and AsyncOperationManager to enable your asynchronous
operations, see Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern.
Guidelines
Ideally, each method invocation should be independent of others. You should avoid coupling invocations
with shared resources. If resources are to be shared among invocations, you will need to provide a proper
synchronization mechanism in your implementation.
Designs that require the client to implement synchronization are discouraged. For example, you could
have an asynchronous method that receives a global static object as a parameter; multiple concurrent
invocations of such a method could result in data corruption or deadlocks.
If you implement a method with the multiple-invocation overload ( userState in the signature), your class
will need to manage a collection of user states, or task IDs, and their corresponding pending operations.
This collection should be protected with lock regions, because the various invocations add and remove
userState objects in the collection.
Consider reusing CompletedEventArgs classes where feasible and appropriate. In this case, the naming is
not consistent with the method name, because a given delegate and EventArgs type are not tied to a single
method. However, forcing developers to cast the value retrieved from a property on the EventArgs is never
acceptable.
If you are authoring a class that derives from Component, do not implement and install your own
SynchronizationContext class. Application models, not components, control the SynchronizationContext
that is used.
When you use multithreading of any sort, you potentially expose yourself to very serious and complex
bugs. Before implementing any solution that uses multithreading, see Managed Threading Best Practices.
See Also
AsyncOperation
AsyncOperationManager
AsyncCompletedEventArgs
ProgressChangedEventArgs
BackgroundWorker
Implementing the Event-based Asynchronous Pattern
Multithreaded Programming with the Event-based Asynchronous Pattern
Deciding When to Implement the Event-based Asynchronous Pattern
Best Practices for Implementing the Event-based Asynchronous Pattern
How to: Use Components That Support the Event-based Asynchronous Pattern
Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern
Deciding When to Implement the Event-based
Asynchronous Pattern
7/29/2017 • 3 min to read • Edit Online
The Event-based Asynchronous Pattern provides a pattern for exposing the asynchronous behavior of a class.
With the introduction of this pattern, the .NET Framework defines two patterns for exposing asynchronous
behavior: the Asynchronous Pattern based on the System.IAsyncResult interface, and the event-based pattern. This
topic describes when it is appropriate for you to implement both patterns.
For more information about asynchronous programming with the IAsyncResult interface, see Event-based
Asynchronous Pattern (EAP).
General Principles
In general, you should expose asynchronous features using the Event-based Asynchronous Pattern whenever
possible. However, there are some requirements that the event-based pattern cannot meet. In those cases, you
may need to implement the IAsyncResult pattern in addition to the event-based pattern.
NOTE
It is rare for the IAsyncResult pattern to be implemented without the event-based pattern also being implemented.
Guidelines
The following list describes the guidelines for when you should implement Event-based Asynchronous Pattern:
Use the event-based pattern as the default API to expose asynchronous behavior for your class.
Do not expose the IAsyncResult pattern when your class is primarily used in a client application, for
example Windows Forms.
Only expose the IAsyncResult pattern when it is necessary for meeting your requirements. For example,
compatibility with an existing API may require you to expose the IAsyncResult pattern.
Do not expose the IAsyncResult pattern without also exposing the event-based pattern.
If you must expose the IAsyncResult pattern, do so as an advanced option. For example, if you generate a
proxy object, generate the event-based pattern by default, with an option to generate the IAsyncResult
pattern.
Build your event-based pattern implementation on your IAsyncResult pattern implementation.
Avoid exposing both the event-based pattern and the IAsyncResult pattern on the same class. Expose the
event-based pattern on "higher level" classes and the IAsyncResult pattern on "lower level" classes. For
example, compare the event-based pattern on the WebClient component with the IAsyncResult pattern on
the HttpRequest class.
Expose the event-based pattern and the IAsyncResult pattern on the same class when compatibility
requires it. For example, if you have already released an API that uses the IAsyncResult pattern, you
would need to retain the IAsyncResult pattern for backward compatibility.
Expose the event-based pattern and the IAsyncResult pattern on the same class if the resulting
object model complexity outweighs the benefit of separating the implementations. It is better to
expose both patterns on a single class than to avoid exposing the event-based pattern.
If you must expose both the event-based pattern and IAsyncResult pattern on a single class, use
EditorBrowsableAttribute set to Advanced to mark the IAsyncResult pattern implementation as an
advanced feature. This indicates to design environments, such as Visual Studio IntelliSense, not to
display the IAsyncResult properties and methods. These properties and methods are still fully usable,
but the developer working through IntelliSense has a clearer view of the API.
See Also
Walkthrough: Implementing a Component That Supports the Event-based Asynchronous Pattern
Event-based Asynchronous Pattern (EAP)
Multithreaded Programming with the Event-based Asynchronous Pattern
Implementing the Event-based Asynchronous Pattern
Best Practices for Implementing the Event-based Asynchronous Pattern
Event-based Asynchronous Pattern Overview
Walkthrough: Implementing a Component That
Supports the Event-based Asynchronous Pattern
7/29/2017 • 21 min to read • Edit Online
If you are writing a class with some operations that may incur noticeable delays, consider giving it asynchronous
functionality by implementing the Event-based Asynchronous Pattern Overview.
This walkthrough illustrates how to create a component that implements the Event-based Asynchronous Pattern. It
is implemented using helper classes from the System.ComponentModel namespace, which ensures that the
component works correctly under any application model, including ASP.NET, Console applications and Windows
Forms applications. This component is also designable with a PropertyGrid control and your own custom designers.
When you are through, you will have an application that computes prime numbers asynchronously. Your
application will have a main user interface (UI) thread and a thread for each prime number calculation. Although
testing whether a large number is prime can take a noticeable amount of time, the main UI thread will not be
interrupted by this delay, and the form will be responsive during the calculations. You will be able to run as many
calculations as you like concurrently and selectively cancel pending calculations.
Tasks illustrated in this walkthrough include:
Creating the Component
Defining Public Asynchronous Events and Delegates
Defining Private Delegates
Implementing Public Events
Implementing the Completion Method
Implementing the Worker Methods
Implementing Start and Cancel Methods
To copy the code in this topic as a single listing, see How to: Implement a Component That Supports the Event-
based Asynchronous Pattern.
Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.Drawing
Imports System.Globalization
Imports System.Threading
Imports System.Windows.Forms
2. Before the PrimeNumberCalculator class definition, declare delegates for progress and completion events.
3. In the PrimeNumberCalculator class definition, declare events for reporting progress and completion to
clients.
4. After the PrimeNumberCalculator class definition, derive the CalculatePrimeCompletedEventArgs class for
reporting the outcome of each calculation to the client's event handler for the CalculatePrimeCompleted
.event. In addition to the AsyncCompletedEventArgs properties, this class enables the client to determine what
number was tested, whether it is prime, and what the first divisor is if it is not prime.
public class CalculatePrimeCompletedEventArgs :
AsyncCompletedEventArgs
{
private int numberToTestValue = 0;
private int firstDivisorValue = 1;
private bool isPrimeValue;
public CalculatePrimeCompletedEventArgs(
int numberToTest,
int firstDivisor,
bool isPrime,
Exception e,
bool canceled,
object state) : base(e, canceled, state)
{
this.numberToTestValue = numberToTest;
this.firstDivisorValue = firstDivisor;
this.isPrimeValue = isPrime;
}
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
You will receive two compiler warnings:
InitializeDelegates();
}
InitializeComponent()
InitializeDelegates()
End Sub
3. Declare a delegate in the PrimeNumberCalculator class that handles the actual work to be done
asynchronously. This delegate wraps the worker method that tests whether a number is prime. The delegate
takes an AsyncOperation parameter, which will be used to track the lifetime of the asynchronous operation.
4. Create a collection for managing lifetimes of pending asynchronous operations. The client needs a way to
track operations as they are executed and completed, and this tracking is done by requiring the client to pass
a unique token, or task ID, when the client makes the call to the asynchronous method. The
PrimeNumberCalculator component must keep track of each call by associating the task ID with its
corresponding invocation. If the client passes a task ID that is not unique, the PrimeNumberCalculator
component must raise an exception.
The PrimeNumberCalculator component keeps track of task ID by using a special collection class called a
HybridDictionary. In the class definition, create a HybridDictionary called userTokenToLifetime .
OnCalculatePrimeCompleted(e);
}
OnProgressChanged(e);
}
OnCalculatePrimeCompleted(e)
End Sub
OnProgressChanged(e)
End Sub
RaiseEvent CalculatePrimeCompleted(Me, e)
End Sub
RaiseEvent ProgressChanged(e)
End Sub
{
// If the task was not previously canceled,
// remove the task from the lifetime collection.
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
You will receive one compiler warning:
NOTE
Progress reporting is implemented in the BuildPrimeNumberList method. On fast computers, ProgressChanged events
can be raised in rapid succession. The client thread, on which these events are raised, must be able to handle this situation.
User interface code may be flooded with messages and unable to keep up, resulting in hanging behavior. For an example user
interface that handles this situation, see How to: Implement a Client of the Event-based Asynchronous Pattern.
2. Implement the CalculateWorker method. It takes two parameters: a number to test, and an AsyncOperation.
// This method performs the actual prime number computation.
// It is executed on the worker thread.
private void CalculateWorker(
int numberToTest,
AsyncOperation asyncOp)
{
bool isPrime = false;
int firstDivisor = 1;
Exception e = null;
//this.CompletionMethod(calcState);
this.CompletionMethod(
numberToTest,
firstDivisor,
isPrime,
e,
TaskCanceled(asyncOp.UserSuppliedState),
asyncOp);
//completionMethodDelegate(calcState);
}
' This method performs the actual prime number computation.
' It is executed on the worker thread.
Private Sub CalculateWorker( _
ByVal numberToTest As Integer, _
ByVal asyncOp As AsyncOperation)
Try
' Find all the prime numbers up to the
' square root of numberToTest.
Dim primes As ArrayList = BuildPrimeNumberList( _
numberToTest, asyncOp)
Catch ex As Exception
exc = ex
End Try
End If
Me.CompletionMethod( _
numberToTest, _
firstDivisor, _
prime, _
exc, _
TaskCanceled(asyncOp.UserSuppliedState), _
asyncOp)
End Sub
3. Implement BuildPrimeNumberList . It takes two parameters: the number to test, and an AsyncOperation. It
uses the AsyncOperation to report progress and incremental results. This assures that the client's event
handlers are called on the proper thread or context for the application model. When BuildPrimeNumberList
finds a prime number, it reports this as an incremental result to the client's event handler for the
ProgressChanged event. This requires a class derived from ProgressChangedEventArgs, called
CalculatePrimeProgressChangedEventArgs , which has one added property called LatestPrimeNumber .
The BuildPrimeNumberList method also periodically calls the TaskCanceled method and exits if the method
returns true .
// This method computes the list of prime numbers used by the
// IsPrime method.
private ArrayList BuildPrimeNumberList(
int numberToTest,
AsyncOperation asyncOp)
{
ProgressChangedEventArgs e = null;
ArrayList primes = new ArrayList();
int firstDivisor;
int n = 5;
// Do the work.
while (n < numberToTest &&
!TaskCanceled( asyncOp.UserSuppliedState ) )
{
if (IsPrime(primes, n, out firstDivisor))
{
// Report to the client that a prime was found.
e = new CalculatePrimeProgressChangedEventArgs(
n,
(int)((float)n / (float)numberToTest * 100),
asyncOp.UserSuppliedState);
asyncOp.Post(this.onProgressReportDelegate, e);
primes.Add(n);
return primes;
}
' This method computes the list of prime numbers used by the
' IsPrime method.
Private Function BuildPrimeNumberList( _
ByVal numberToTest As Integer, _
ByVal asyncOp As AsyncOperation) As ArrayList
asyncOp.Post(Me.onProgressReportDelegate, e)
primes.Add(n)
End While
Return primes
End Function
4. Implement IsPrime . It takes three parameters: a list of known prime numbers, the number to test, and an
output parameter for the first divisor found. Given the list of prime numbers, it determines if the test number
is prime.
// This method tests n for primality against the list of
// prime numbers contained in the primes parameter.
private bool IsPrime(
ArrayList primes,
int n,
out int firstDivisor)
{
bool foundDivisor = false;
bool exceedsSquareRoot = false;
int i = 0;
int divisor = 0;
firstDivisor = 1;
return !foundDivisor;
}
' This method tests n for primality against the list of
' prime numbers contained in the primes parameter.
Private Function IsPrime( _
ByVal primes As ArrayList, _
ByVal n As Integer, _
ByRef firstDivisor As Integer) As Boolean
Dim i As Integer = 0
Dim divisor As Integer = 0
firstDivisor = 1
End Function
public CalculatePrimeProgressChangedEventArgs(
int latestPrime,
int progressPercentage,
object userToken) : base( progressPercentage, userToken )
{
this.latestPrimeNumberValue = latestPrime;
}
MyBase.New(progressPercentage, UserState)
Me.latestPrimeNumberValue = latestPrime
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
All that remains to be written are the methods to start and cancel asynchronous operations,
CalculatePrimeAsync and CancelAsync .
userStateToLifetime[taskId] = asyncOp;
}
userStateToLifetime(taskId) = asyncOp
End SyncLock
workerDelegate.BeginInvoke( _
numberToTest, _
asyncOp, _
Nothing, _
Nothing)
End Sub
2. Implement the CancelAsync method. If the taskId parameter exists in the token collection, it is removed.
This prevents canceled tasks that have not started from running. If the task is running, the
BuildPrimeNumberList method exits when it detects that the task ID has been removed from the lifetime
collection.
SyncLock userStateToLifetime.SyncRoot
userStateToLifetime.Remove(taskId)
End SyncLock
End If
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
The PrimeNumberCalculator component is now complete and ready to use.
For an example client that uses the PrimeNumberCalculator component, see How to: Implement a Client of the Event-
based Asynchronous Pattern.
Next Steps
You can fill out this example by writing CalculatePrime , the synchronous equivalent of CalculatePrimeAsync
method. This will make the PrimeNumberCalculator component fully compliant with the Event-based Asynchronous
Pattern.
You can improve this example by retaining the list of all the prime numbers discovered by various invocations for
different test numbers. Using this approach, each task will benefit from the work done by previous tasks. Be careful
to protect this list with lock regions, so access to the list by different threads is serialized.
You can also improve this example by testing for trivial divisors, like 2, 3, and 5.
See Also
How to: Run an Operation in the Background
Event-based Asynchronous Pattern Overview
NOT IN BUILD: Multithreading in Visual Basic
How to: Implement a Component That Supports the Event-based Asynchronous Pattern
Multithreaded Programming with the Event-based Asynchronous Pattern
Walkthrough: Implementing a Component That
Supports the Event-based Asynchronous Pattern
7/29/2017 • 21 min to read • Edit Online
If you are writing a class with some operations that may incur noticeable delays, consider giving it asynchronous
functionality by implementing the Event-based Asynchronous Pattern Overview.
This walkthrough illustrates how to create a component that implements the Event-based Asynchronous Pattern.
It is implemented using helper classes from the System.ComponentModel namespace, which ensures that the
component works correctly under any application model, including ASP.NET, Console applications and Windows
Forms applications. This component is also designable with a PropertyGrid control and your own custom
designers.
When you are through, you will have an application that computes prime numbers asynchronously. Your
application will have a main user interface (UI) thread and a thread for each prime number calculation. Although
testing whether a large number is prime can take a noticeable amount of time, the main UI thread will not be
interrupted by this delay, and the form will be responsive during the calculations. You will be able to run as
many calculations as you like concurrently and selectively cancel pending calculations.
Tasks illustrated in this walkthrough include:
Creating the Component
Defining Public Asynchronous Events and Delegates
Defining Private Delegates
Implementing Public Events
Implementing the Completion Method
Implementing the Worker Methods
Implementing Start and Cancel Methods
To copy the code in this topic as a single listing, see How to: Implement a Component That Supports the Event-
based Asynchronous Pattern.
Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.Drawing
Imports System.Globalization
Imports System.Threading
Imports System.Windows.Forms
2. Before the PrimeNumberCalculator class definition, declare delegates for progress and completion events.
3. In the PrimeNumberCalculator class definition, declare events for reporting progress and completion to
clients.
4. After the PrimeNumberCalculator class definition, derive the CalculatePrimeCompletedEventArgs class for
reporting the outcome of each calculation to the client's event handler for the CalculatePrimeCompleted
.event. In addition to the AsyncCompletedEventArgs properties, this class enables the client to determine
what number was tested, whether it is prime, and what the first divisor is if it is not prime.
public class CalculatePrimeCompletedEventArgs :
AsyncCompletedEventArgs
{
private int numberToTestValue = 0;
private int firstDivisorValue = 1;
private bool isPrimeValue;
public CalculatePrimeCompletedEventArgs(
int numberToTest,
int firstDivisor,
bool isPrime,
Exception e,
bool canceled,
object state) : base(e, canceled, state)
{
this.numberToTestValue = numberToTest;
this.firstDivisorValue = firstDivisor;
this.isPrimeValue = isPrime;
}
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
You will receive two compiler warnings:
InitializeDelegates();
}
InitializeComponent()
InitializeDelegates()
End Sub
3. Declare a delegate in the PrimeNumberCalculator class that handles the actual work to be done
asynchronously. This delegate wraps the worker method that tests whether a number is prime. The
delegate takes an AsyncOperation parameter, which will be used to track the lifetime of the asynchronous
operation.
4. Create a collection for managing lifetimes of pending asynchronous operations. The client needs a way to
track operations as they are executed and completed, and this tracking is done by requiring the client to
pass a unique token, or task ID, when the client makes the call to the asynchronous method. The
PrimeNumberCalculator component must keep track of each call by associating the task ID with its
corresponding invocation. If the client passes a task ID that is not unique, the PrimeNumberCalculator
component must raise an exception.
The PrimeNumberCalculator component keeps track of task ID by using a special collection class called a
HybridDictionary. In the class definition, create a HybridDictionary called userTokenToLifetime .
OnCalculatePrimeCompleted(e);
}
OnProgressChanged(e);
}
OnCalculatePrimeCompleted(e)
End Sub
OnProgressChanged(e)
End Sub
RaiseEvent CalculatePrimeCompleted(Me, e)
End Sub
RaiseEvent ProgressChanged(e)
End Sub
{
// If the task was not previously canceled,
// remove the task from the lifetime collection.
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
You will receive one compiler warning:
NOTE
Progress reporting is implemented in the BuildPrimeNumberList method. On fast computers, ProgressChanged events
can be raised in rapid succession. The client thread, on which these events are raised, must be able to handle this situation.
User interface code may be flooded with messages and unable to keep up, resulting in hanging behavior. For an example
user interface that handles this situation, see How to: Implement a Client of the Event-based Asynchronous Pattern.
2. Implement the CalculateWorker method. It takes two parameters: a number to test, and an
AsyncOperation.
// This method performs the actual prime number computation.
// It is executed on the worker thread.
private void CalculateWorker(
int numberToTest,
AsyncOperation asyncOp)
{
bool isPrime = false;
int firstDivisor = 1;
Exception e = null;
//this.CompletionMethod(calcState);
this.CompletionMethod(
numberToTest,
firstDivisor,
isPrime,
e,
TaskCanceled(asyncOp.UserSuppliedState),
asyncOp);
//completionMethodDelegate(calcState);
}
' This method performs the actual prime number computation.
' It is executed on the worker thread.
Private Sub CalculateWorker( _
ByVal numberToTest As Integer, _
ByVal asyncOp As AsyncOperation)
Try
' Find all the prime numbers up to the
' square root of numberToTest.
Dim primes As ArrayList = BuildPrimeNumberList( _
numberToTest, asyncOp)
Catch ex As Exception
exc = ex
End Try
End If
Me.CompletionMethod( _
numberToTest, _
firstDivisor, _
prime, _
exc, _
TaskCanceled(asyncOp.UserSuppliedState), _
asyncOp)
End Sub
3. Implement BuildPrimeNumberList . It takes two parameters: the number to test, and an AsyncOperation. It
uses the AsyncOperation to report progress and incremental results. This assures that the client's event
handlers are called on the proper thread or context for the application model. When
BuildPrimeNumberList finds a prime number, it reports this as an incremental result to the client's event
handler for the ProgressChanged event. This requires a class derived from ProgressChangedEventArgs,
called CalculatePrimeProgressChangedEventArgs , which has one added property called LatestPrimeNumber .
The BuildPrimeNumberList method also periodically calls the TaskCanceled method and exits if the
method returns true .
// This method computes the list of prime numbers used by the
// IsPrime method.
private ArrayList BuildPrimeNumberList(
int numberToTest,
AsyncOperation asyncOp)
{
ProgressChangedEventArgs e = null;
ArrayList primes = new ArrayList();
int firstDivisor;
int n = 5;
// Do the work.
while (n < numberToTest &&
!TaskCanceled( asyncOp.UserSuppliedState ) )
{
if (IsPrime(primes, n, out firstDivisor))
{
// Report to the client that a prime was found.
e = new CalculatePrimeProgressChangedEventArgs(
n,
(int)((float)n / (float)numberToTest * 100),
asyncOp.UserSuppliedState);
asyncOp.Post(this.onProgressReportDelegate, e);
primes.Add(n);
return primes;
}
' This method computes the list of prime numbers used by the
' IsPrime method.
Private Function BuildPrimeNumberList( _
ByVal numberToTest As Integer, _
ByVal asyncOp As AsyncOperation) As ArrayList
asyncOp.Post(Me.onProgressReportDelegate, e)
primes.Add(n)
End While
Return primes
End Function
4. Implement IsPrime . It takes three parameters: a list of known prime numbers, the number to test, and an
output parameter for the first divisor found. Given the list of prime numbers, it determines if the test
number is prime.
// This method tests n for primality against the list of
// prime numbers contained in the primes parameter.
private bool IsPrime(
ArrayList primes,
int n,
out int firstDivisor)
{
bool foundDivisor = false;
bool exceedsSquareRoot = false;
int i = 0;
int divisor = 0;
firstDivisor = 1;
return !foundDivisor;
}
' This method tests n for primality against the list of
' prime numbers contained in the primes parameter.
Private Function IsPrime( _
ByVal primes As ArrayList, _
ByVal n As Integer, _
ByRef firstDivisor As Integer) As Boolean
Dim i As Integer = 0
Dim divisor As Integer = 0
firstDivisor = 1
End Function
public CalculatePrimeProgressChangedEventArgs(
int latestPrime,
int progressPercentage,
object userToken) : base( progressPercentage, userToken )
{
this.latestPrimeNumberValue = latestPrime;
}
MyBase.New(progressPercentage, UserState)
Me.latestPrimeNumberValue = latestPrime
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
All that remains to be written are the methods to start and cancel asynchronous operations,
CalculatePrimeAsync and CancelAsync .
userStateToLifetime[taskId] = asyncOp;
}
userStateToLifetime(taskId) = asyncOp
End SyncLock
workerDelegate.BeginInvoke( _
numberToTest, _
asyncOp, _
Nothing, _
Nothing)
End Sub
2. Implement the CancelAsync method. If the taskId parameter exists in the token collection, it is removed.
This prevents canceled tasks that have not started from running. If the task is running, the
BuildPrimeNumberList method exits when it detects that the task ID has been removed from the lifetime
collection.
SyncLock userStateToLifetime.SyncRoot
userStateToLifetime.Remove(taskId)
End SyncLock
End If
End Sub
Checkpoint
At this point, you can build the component.
To test your component
Compile the component.
The PrimeNumberCalculator component is now complete and ready to use.
For an example client that uses the PrimeNumberCalculator component, see How to: Implement a Client of the
Event-based Asynchronous Pattern.
Next Steps
You can fill out this example by writing CalculatePrime , the synchronous equivalent of CalculatePrimeAsync
method. This will make the PrimeNumberCalculator component fully compliant with the Event-based
Asynchronous Pattern.
You can improve this example by retaining the list of all the prime numbers discovered by various invocations
for different test numbers. Using this approach, each task will benefit from the work done by previous tasks. Be
careful to protect this list with lock regions, so access to the list by different threads is serialized.
You can also improve this example by testing for trivial divisors, like 2, 3, and 5.
See Also
How to: Run an Operation in the Background
Event-based Asynchronous Pattern Overview
NOT IN BUILD: Multithreading in Visual Basic
How to: Implement a Component That Supports the Event-based Asynchronous Pattern
Multithreaded Programming with the Event-based Asynchronous Pattern
How to: Implement a Client of the Event-based
Asynchronous Pattern
7/29/2017 • 26 min to read • Edit Online
The following code example demonstrates how to use a component that adheres to the Event-based
Asynchronous Pattern Overview. The form for this example uses the PrimeNumberCalculator component described
in How to: Implement a Component That Supports the Event-based Asynchronous Pattern.
When you run a project that uses this example, you will see a "Prime Number Calculator" form with a grid and two
buttons: Start New Task and Cancel. You can click the Start New Task button several times in succession, and
for each click, an asynchronous operation will begin a computation to determine if a randomly generated test
number is prime. The form will periodically display progress and incremental results. Each operation is assigned a
unique task ID. The result of the computation is displayed in the Result column; if the test number is not prime, it
is labeled as Composite, and its first divisor is displayed.
Any pending operation can be canceled with the Cancel button. Multiple selections can be made.
NOTE
Most numbers will not be prime. If you have not found a prime number after several completed operations, simply start
more tasks, and eventually you will find some prime numbers.
Example
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Threading;
using System.Windows.Forms;
namespace AsyncOperationManagerExample
{
// This form tests the PrimeNumberCalculator component.
public class PrimeNumberCalculatorMain : System.Windows.Forms.Form
{
/////////////////////////////////////////////////////////////
// Private fields
//
#region Private fields
/////////////////////////////////////////////////////////////
// Construction and destruction
//
#region Private fields
public PrimeNumberCalculatorMain ()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
this.primeNumberCalculator1.ProgressChanged +=
new ProgressChangedEventHandler(
primeNumberCalculator1_ProgressChanged);
this.listView1.SelectedIndexChanged +=
new EventHandler(listView1_SelectedIndexChanged);
}
/////////////////////////////////////////////////////////////
//
#region Implementation
cancelButton.Enabled = false;
}
if (e is CalculatePrimeProgressChangedEventArgs)
{
CalculatePrimeProgressChangedEventArgs cppcea =
e as CalculatePrimeProgressChangedEventArgs;
this.UpdateListViewItem(
taskId,
cppcea.ProgressPercentage,
cppcea.LatestPrimeNumber);
}
else
{
this.UpdateListViewItem(
taskId,
e.ProgressPercentage);
}
}
else if (this.progressCounter > this.progressInterval)
{
this.progressCounter = 0;
}
}
if (e.Cancelled)
{
string result = "Canceled";
if (lvi != null)
{
lvi.BackColor = Color.Pink;
lvi.Tag = null;
}
}
else if (e.Error != null)
{
string result = "Error";
if (lvi != null)
{
lvi.BackColor = Color.Red;
lvi.ForeColor = Color.White;
lvi.Tag = null;
}
}
else
{
bool result = e.IsPrime;
if (lvi != null)
{
lvi.BackColor = Color.LightGray;
lvi.Tag = null;
}
}
}
#endregion // Implementation
/////////////////////////////////////////////////////////////
//
#region Private Methods
lvi.SubItems.Add("Not Started");
lvi.SubItems.Add("1");
lvi.SubItems.Add(guid.ToString());
lvi.SubItems.Add("---");
lvi.SubItems.Add("---");
lvi.Tag = guid;
this.listView1.Items.Add( lvi );
return lvi;
}
return lviRet;
}
lviRet = lvi;
lviRet = lvi;
break;
}
}
return lviRet;
}
return lviRet;
}
return lviRet;
}
return lviRet;
}
#endregion
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new PrimeNumberCalculatorMain());
}
/////////////////////////////////////////////////////////////
#region PrimeNumberCalculator Implementation
/////////////////////////////////////////////////////////////
#region Public events
#endregion
/////////////////////////////////////////////////////////////
#region Construction and destruction
public PrimeNumberCalculator(IContainer container)
{
container.Add(this);
InitializeComponent();
InitializeDelegates();
}
public PrimeNumberCalculator()
{
InitializeComponent();
InitializeDelegates();
}
/////////////////////////////////////////////////////////////
///
#region Implementation
userStateToLifetime[taskId] = asyncOp;
}
//this.CompletionMethod(calcState);
this.CompletionMethod(
numberToTest,
firstDivisor,
isPrime,
e,
TaskCanceled(asyncOp.UserSuppliedState),
asyncOp);
//completionMethodDelegate(calcState);
}
// Do the work.
while (n < numberToTest &&
!TaskCanceled( asyncOp.UserSuppliedState ) )
{
if (IsPrime(primes, n, out firstDivisor))
{
// Report to the client that a prime was found.
e = new CalculatePrimeProgressChangedEventArgs(
n,
(int)((float)n / (float)numberToTest * 100),
asyncOp.UserSuppliedState);
asyncOp.Post(this.onProgressReportDelegate, e);
primes.Add(n);
return primes;
}
int i = 0;
int i = 0;
int divisor = 0;
firstDivisor = 1;
return !foundDivisor;
}
OnCalculatePrimeCompleted(e);
}
OnProgressChanged(e);
}
{
// If the task was not previously canceled,
// remove the task from the lifetime collection.
if (!canceled)
{
lock (userStateToLifetime.SyncRoot)
{
userStateToLifetime.Remove(asyncOp.UserSuppliedState);
}
}
#endregion
/////////////////////////////////////////////////////////////
#region Component Designer generated code
#endregion
public CalculatePrimeProgressChangedEventArgs(
int latestPrime,
int progressPercentage,
object userToken) : base( progressPercentage, userToken )
{
{
this.latestPrimeNumberValue = latestPrime;
}
public CalculatePrimeCompletedEventArgs(
int numberToTest,
int firstDivisor,
bool isPrime,
Exception e,
bool canceled,
object state) : base(e, canceled, state)
{
this.numberToTestValue = numberToTest;
this.firstDivisorValue = firstDivisor;
this.isPrimeValue = isPrime;
}
#endregion
Imports System
Imports System.Collections
Imports System.Collections.Specialized
Imports System.ComponentModel
Imports System.Drawing
Imports System.Globalization
Imports System.Threading
Imports System.Windows.Forms
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Private fields
'
#Region "Private fields"
#End Region
InitializeComponent()
End Sub
End Sub
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#Region "Implementation"
End Sub
Me.cancelAsyncButton.Enabled = CanCancel()
End Sub
' This event handler cancels all pending tasks that are
' selected in the ListView control.
Private Sub cancelAsyncButton_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles cancelAsyncButton.Click
cancelAsyncButton.Enabled = False
End Sub
' This event handler updates the ListView control when the
' PrimeNumberCalculator raises the ProgressChanged event.
'
' On fast computers, the PrimeNumberCalculator can raise many
' successive ProgressChanged events, so the user interface
' may be flooded with messages. To prevent the user interface
' from hanging, progress is only reported at intervals.
Private Sub primeNumberCalculator1_ProgressChanged( _
ByVal e As ProgressChangedEventArgs) _
Handles primeNumberCalculator1.ProgressChanged
Me.progressCounter += 1
End Sub
' This event handler updates the ListView control when the
' PrimeNumberCalculator raises the CalculatePrimeCompleted
' event. The ListView item is updated with the appropriate
' outcome of the calculation: Canceled, Error, or result.
Private Sub primeNumberCalculator1_CalculatePrimeCompleted( _
ByVal sender As Object, _
ByVal e As CalculatePrimeCompletedEventArgs) _
Handles primeNumberCalculator1.CalculatePrimeCompleted
If e.Cancelled Then
Dim result As String = "Canceled"
End Sub
#End Region
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#Region "Private Methods"
lvi.SubItems.Add("Not Started")
lvi.SubItems.Add("1")
lvi.SubItems.Add(guid.ToString())
lvi.SubItems.Add("---")
lvi.SubItems.Add("---")
lvi.Tag = guid
Me.listView1.Items.Add(lvi)
Return lvi
End Function
Return lviRet
End Function
lviRet = lvi
Exit For
End If
Next lvi
Return lviRet
End Function
Return lviRet
End Function
Return lviRet
End Function
Return lviRet
End Function
End Function
#End Region
End Sub
<STAThread()> _
Shared Sub Main()
Application.Run(New PrimeNumberCalculatorMain())
End Sub
End Class
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#Region "Public events"
#End Region
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#Region "Construction and destruction"
container.Add(Me)
InitializeComponent()
InitializeDelegates()
End Sub
InitializeComponent()
InitializeDelegates()
End Sub
End Sub
#End Region
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#Region "Implementation"
workerDelegate.BeginInvoke( _
numberToTest, _
asyncOp, _
Nothing, _
Nothing)
End Sub
SyncLock userStateToLifetime.SyncRoot
userStateToLifetime.Remove(taskId)
End SyncLock
End If
End Sub
Try
' Find all the prime numbers up to the
' square root of numberToTest.
Dim primes As ArrayList = BuildPrimeNumberList( _
numberToTest, asyncOp)
Catch ex As Exception
exc = ex
End Try
End If
Me.CompletionMethod( _
numberToTest, _
firstDivisor, _
prime, _
exc, _
TaskCanceled(asyncOp.UserSuppliedState), _
asyncOp)
End Sub
' This method computes the list of prime numbers used by the
' IsPrime method.
Private Function BuildPrimeNumberList( _
ByVal numberToTest As Integer, _
ByVal asyncOp As AsyncOperation) As ArrayList
asyncOp.Post(Me.onProgressReportDelegate, e)
primes.Add(n)
End While
Return primes
End Function
Dim i As Integer = 0
Dim divisor As Integer = 0
firstDivisor = 1
firstDivisor = 1
End Function
OnCalculatePrimeCompleted(e)
End Sub
OnProgressChanged(e)
End Sub
RaiseEvent CalculatePrimeCompleted(Me, e)
End Sub
RaiseEvent ProgressChanged(e)
End Sub
End Sub
#End Region
End Sub
End Class
MyBase.New(progressPercentage, UserState)
Me.latestPrimeNumberValue = latestPrime
End Sub
End Sub
See Also
AsyncOperation
AsyncOperationManager
WindowsFormsSynchronizationContext
How to: Use Components That Support the Event-
based Asynchronous Pattern
7/29/2017 • 1 min to read • Edit Online
Many components provide you with the option of performing their work asynchronously. The SoundPlayer and
PictureBox components, for example, enable you to load sounds and images "in the background" while your main
thread continues running without interruption.
Using asynchronous methods on a class that supports the Event-based Asynchronous Pattern Overview can be as
simple as attaching an event handler to the component's MethodName Completed event, just as you would for any
other event. When you call the MethodName Async method, your application will continue running without
interruption until the MethodName Completed event is raised. In your event handler, you can examine the
AsyncCompletedEventArgs parameter to determine if the asynchronous operation successfully completed or if it
was canceled.
For more information about using event handlers, see Event Handlers Overview.
The following procedure shows how to use the asynchronous image-loading capability of a PictureBox control.
To enable a PictureBox control to asynchronously load an image
1. Create an instance of the PictureBox component in your form.
2. Assign an event handler to the LoadCompleted event.
Check for any errors that may have occurred during the asynchronous download here. This is also where
you check for cancellation.
public Form1()
{
InitializeComponent();
this.pictureBox1.LoadCompleted +=
new System.ComponentModel.AsyncCompletedEventHandler(this.pictureBox1_LoadCompleted);
}
End Sub
3. Add two buttons, called loadButton and cancelLoadButton , to your form. Add Click event handlers to start
and cancel the download.
End Sub
PictureBox1.CancelAsync()
End Sub
See Also
How to: Run an Operation in the Background
Event-based Asynchronous Pattern Overview
NOT IN BUILD: Multithreading in Visual Basic
Asynchronous Programming Model (APM)
7/29/2017 • 4 min to read • Edit Online
An asynchronous operation that uses the IAsyncResult design pattern is implemented as two methods named
Begin OperationName and End OperationName that begin and end the asynchronous operation
OperationName respectively. For example, the FileStream class provides the BeginRead and EndRead methods to
asynchronously read bytes from a file. These methods implement the asynchronous version of the Read method.
NOTE
Starting with the .NET Framework 4, the Task Parallel Library provides a new model for asynchronous and parallel
programming. For more information, see Task Parallel Library (TPL) and Task-based Asynchronous Pattern (TAP)).
After calling Begin OperationName, an application can continue executing instructions on the calling thread while
the asynchronous operation takes place on a different thread. For each call to Begin OperationName, the
application should also call End OperationName to get the results of the operation.
MEMBER DESCRIPTION
A Begin OperationName method takes any parameters declared in the signature of the synchronous version of
the method that are passed by value or by reference. Any out parameters are not part of the Begin
OperationName method signature. The Begin OperationName method signature also includes two additional
parameters. The first of these defines an AsyncCallback delegate that references a method that is called when the
asynchronous operation completes. The caller can specify null ( Nothing in Visual Basic) if it does not want a
method invoked when the operation completes. The second additional parameter is a user-defined object. This
object can be used to pass application-specific state information to the method invoked when the asynchronous
operation completes. If a Begin OperationName method takes additional operation-specific parameters, such as a
byte array to store bytes read from a file, the AsyncCallback and application state object are the last parameters in
the Begin OperationName method signature.
Begin OperationName returns control to the calling thread immediately. If the Begin OperationName method
throws exceptions, the exceptions are thrown before the asynchronous operation is started. If the Begin
OperationName method throws exceptions, the callback method is not invoked.
NOTE
For either of the undefined scenarios, implementers should consider throwing InvalidOperationException.
NOTE
Implementers of this design pattern should notify the caller that the asynchronous operation completed by setting
IsCompleted to true, calling the asynchronous callback method (if one was specified) and signaling the AsyncWaitHandle.
Application developers have several design choices for accessing the results of the asynchronous operation. The
correct choice depends on whether the application has instructions that can execute while the operation
completes. If an application cannot perform any additional work until it receives the results of the asynchronous
operation, the application must block until the results are available. To block until an asynchronous operation
completes, you can use one of the following approaches:
Call End OperationName from the application’s main thread, blocking application execution until the
operation is complete. For an example that illustrates this technique, see Blocking Application Execution by
Ending an Async Operation.
Use the AsyncWaitHandle to block application execution until one or more operations are complete. For an
example that illustrates this technique, see Blocking Application Execution Using an AsyncWaitHandle.
Applications that do not need to block while the asynchronous operation completes can use one of the following
approaches:
Poll for operation completion status by checking the IsCompleted property periodically and calling End
OperationName when the operation is complete. For an example that illustrates this technique, see Polling
for the Status of an Asynchronous Operation.
Use an AsyncCallback delegate to specify a method to be invoked when the operation is complete. For an
example that illustrates this technique, see Using an AsyncCallback Delegate to End an Asynchronous
Operation.
See Also
Event-based Asynchronous Pattern (EAP)
Calling Synchronous Methods Asynchronously
Using an AsyncCallback Delegate and State Object
Calling Asynchronous Methods Using IAsyncResult
7/29/2017 • 1 min to read • Edit Online
Types in the .NET Framework and third-party class libraries can provide methods that allow an application to
continue executing while performing asynchronous operations in threads other than the main application thread.
The following sections describe and provide code examples that demonstrate the different ways you can call
asynchronous methods that use the IAsyncResult design pattern.
Blocking Application Execution by Ending an Async Operation.
Blocking Application Execution Using an AsyncWaitHandle.
Polling for the Status of an Asynchronous Operation.
Using an AsyncCallback Delegate to End an Asynchronous Operation.
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Blocking Application Execution Using an
AsyncWaitHandle
7/29/2017 • 3 min to read • Edit Online
Applications that cannot continue to do other work while waiting for the results of an asynchronous operation
must block until the operation completes. Use one of the following options to block your application's main thread
while waiting for an asynchronous operation to complete:
Use the AsyncWaitHandle property of the IAsyncResult returned by the asynchronous operation's Begin
OperationName method. This approach is demonstrated in this topic.
Call the asynchronous operation's End OperationName method. For an example that demonstrates this
approach, see Blocking Application Execution by Ending an Async Operation.
Applications that use one or more WaitHandle objects to block until an asynchronous operation is complete will
typically call the Begin OperationName method, perform any work that can be done without the results of the
operation, and then block until the asynchronous operation(s) completes. An application can block on a single
operation by calling one of the WaitOne methods using the AsyncWaitHandle. To block while waiting for a set of
asynchronous operations to complete, store the associated AsyncWaitHandle objects in an array and call one of the
WaitAll methods. To block while waiting for any one of a set of asynchronous operations to complete, store the
associated AsyncWaitHandle objects in an array and call one of the WaitAny methods.
Example
The following code example demonstrates using asynchronous methods in the DNS class to retrieve Domain
Name System information for a user-specified computer. The example demonstrates blocking using the
WaitHandle associated with the asynchronous operation. Note that null ( Nothing in Visual Basic) is passed for
the BeginGetHostByName requestCallback and stateObject parameters because these are not required when
using this approach.
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computer.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class WaitUntilOperationCompletes
{
public static void Main(string[] args)
{
// Make sure the caller supplied a host name.
if (args.Length == 0 || args[0].Length == 0)
{
// Print a message and exit.
Console.WriteLine("You must specify the name of a host computer.");
return;
}
// Start the asynchronous request for DNS information.
IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null);
Console.WriteLine("Processing request for information...");
// Wait until the operation completes.
result.AsyncWaitHandle.WaitOne();
// The operation completed. Process the results.
try
{
// Get the results.
IPHostEntry host = Dns.EndGetHostEntry(result);
string[] aliases = host.Aliases;
IPAddress[] addresses = host.AddressList;
if (aliases.Length > 0)
{
Console.WriteLine("Aliases");
for (int i = 0; i < aliases.Length; i++)
{
Console.WriteLine("{0}", aliases[i]);
}
}
if (addresses.Length > 0)
{
Console.WriteLine("Addresses");
for (int i = 0; i < addresses.Length; i++)
{
Console.WriteLine("{0}",addresses[i].ToString());
}
}
}
catch (SocketException e)
{
Console.WriteLine("Exception occurred while processing the request: {0}",
e.Message);
}
}
}
}
' The following example demonstrates using asynchronous methods to
' get Domain Name System information for the specified host computer.
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class WaitUntilOperationCompletes
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Blocking Application Execution by Ending an Async
Operation
7/29/2017 • 2 min to read • Edit Online
Applications that cannot continue to do other work while waiting for the results of an asynchronous operation
must block until the operation completes. Use one of the following options to block your application's main thread
while waiting for an asynchronous operation to complete:
Call the asynchronous operations End OperationName method. This approach is demonstrated in this
topic.
Use the AsyncWaitHandle property of the IAsyncResult returned by the asynchronous operation's Begin
OperationName method. For an example that demonstrates this approach, see Blocking Application
Execution Using an AsyncWaitHandle.
Applications that use the End OperationName method to block until an asynchronous operation is complete will
typically call the Begin OperationName method, perform any work that can be done without the results of the
operation, and then call End OperationName.
Example
The following code example demonstrates using asynchronous methods in the Dns class to retrieve Domain Name
System information for a user-specified computer. Note that null ( Nothing in Visual Basic) is passed for the
BeginGetHostByName requestCallback and stateObject parameters because these arguments are not required
when using this approach.
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computer.
*/
using System;
using System.Net;
using System.Net.Sockets;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class BlockUntilOperationCompletes
{
public static void Main(string[] args)
{
// Make sure the caller supplied a host name.
if (args.Length == 0 || args[0].Length == 0)
{
// Print a message and exit.
Console.WriteLine("You must specify the name of a host computer.");
return;
}
// Start the asynchronous request for DNS information.
// This example does not use a delegate or user-supplied object
// so the last two arguments are null.
IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null);
Console.WriteLine("Processing your request for information...");
// Do any additional work that can be done here.
try
{
// EndGetHostByName blocks until the process completes.
IPHostEntry host = Dns.EndGetHostEntry(result);
string[] aliases = host.Aliases;
IPAddress[] addresses = host.AddressList;
if (aliases.Length > 0)
{
Console.WriteLine("Aliases");
for (int i = 0; i < aliases.Length; i++)
{
Console.WriteLine("{0}", aliases[i]);
}
}
if (addresses.Length > 0)
{
Console.WriteLine("Addresses");
for (int i = 0; i < addresses.Length; i++)
{
Console.WriteLine("{0}",addresses[i].ToString());
}
}
}
catch (SocketException e)
{
Console.WriteLine("An exception occurred while processing the request: {0}", e.Message);
}
}
}
}
' The following example demonstrates using asynchronous methods to
' get Domain Name System information for the specified host computer.
Imports System
Imports System.Net
Imports System.Net.Sockets
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class BlockUntilOperationCompletes
Public Shared Sub Main(args() as String)
' Make sure the caller supplied a host name.
If(args.Length = 0)
' Print a message and exit.
Console.WriteLine("You must specify the name of a host computer.")
End
End If
' Start the asynchronous request for DNS information.
' This example does not use a delegate or user-supplied object
' so the last two arguments are Nothing.
Dim result as IAsyncResult = Dns.BeginGetHostEntry(args(0), Nothing, Nothing)
Console.WriteLine("Processing your request for information...")
' Do any additional work that can be done here.
Try
' EndGetHostByName blocks until the process completes.
Dim host as IPHostEntry = Dns.EndGetHostEntry(result)
Dim aliases() as String = host.Aliases
Dim addresses() as IPAddress= host.AddressList
Dim i as Integer
If aliases.Length > 0
Console.WriteLine("Aliases")
For i = 0 To aliases.Length -1
Console.WriteLine("{0}", aliases(i))
Next i
End If
If addresses.Length > 0
Console.WriteLine("Addresses")
For i = 0 To addresses.Length -1
Console.WriteLine("{0}", addresses(i).ToString())
Next i
End If
Catch e as SocketException
Console.WriteLine("An exception occurred while processing the request: {0}", e.Message)
End Try
End Sub
End Class
End Namespace
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Polling for the Status of an Asynchronous Operation
7/29/2017 • 3 min to read • Edit Online
Applications that can do other work while waiting for the results of an asynchronous operation should not block
waiting until the operation completes. Use one of the following options to continue executing instructions while
waiting for an asynchronous operation to complete:
Use the IsCompleted property of the IAsyncResult returned by the asynchronous operation's Begin
OperationName method to determine whether the operation has completed. This approach is known as
polling and is demonstrated in this topic.
Use an AsyncCallback delegate to process the results of the asynchronous operation in a separate thread.
For an example that demonstrates this approach, see Using an AsyncCallback Delegate to End an
Asynchronous Operation.
Example
The following code example demonstrates using asynchronous methods in the Dns class to retrieve Domain Name
System information for a user-specified computer. This example starts the asynchronous operation and then prints
periods (".") at the console until the operation is complete. Note that null (Nothing in Visual Basic) is passed for
the BeginGetHostByNameAsyncCallback and Object parameters because these arguments are not required when
using this approach.
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computer.
This example polls to detect the end of the asynchronous operation.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class PollUntilOperationCompletes
{
static void UpdateUserInterface()
{
// Print a period to indicate that the application
// is still working on the request.
Console.Write(".");
}
public static void Main(string[] args)
{
// Make sure the caller supplied a host name.
if (args.Length == 0 || args[0].Length == 0)
{
// Print a message and exit.
Console.WriteLine("You must specify the name of a host computer.");
return;
}
// Start the asychronous request for DNS information.
IAsyncResult result = Dns.BeginGetHostEntry(args[0], null, null);
Console.WriteLine("Processing request for information...");
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Namespace Examples.AdvancedProgramming.AsynchronousOperations
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Using an AsyncCallback Delegate to End an
Asynchronous Operation
7/29/2017 • 4 min to read • Edit Online
Applications that can do other work while waiting for the results of an asynchronous operation should not block
waiting until the operation completes. Use one of the following options to continue executing instructions while
waiting for an asynchronous operation to complete:
Use an AsyncCallback delegate to process the results of the asynchronous operation in a separate thread.
This approach is demonstrated in this topic.
Use the IsCompleted property of the IAsyncResult returned by the asynchronous operation's Begin
OperationName method to determine whether the operation has completed. For an example that
demonstrates this approach, see Polling for the Status of an Asynchronous Operation.
Example
The following code example demonstrates using asynchronous methods in the Dns class to retrieve Domain Name
System (DNS) information for user-specified computers. This example creates an AsyncCallback delegate that
references the ProcessDnsInformation method. This method is called once for each asynchronous request for DNS
information.
Note that the user-specified host is passed to the BeginGetHostByNameObject parameter. For an example that
demonstrates defining and using a more complex state object, see Using an AsyncCallback Delegate and State
Object.
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computers.
This example uses a delegate to obtain the results of each asynchronous
operation.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Specialized;
using System.Collections;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class UseDelegateForAsyncCallback
{
static int requestCounter;
static ArrayList hostData = new ArrayList();
static StringCollection hostNames = new StringCollection();
static void UpdateUserInterface()
{
// Print a message to indicate that the application
// is still working on the remaining requests.
Console.WriteLine("{0} requests remaining.", requestCounter);
}
public static void Main()
{
// Create the delegate that will process the results of the
// asynchronous request.
// asynchronous request.
AsyncCallback callBack = new AsyncCallback(ProcessDnsInformation);
string host;
do
{
Console.Write(" Enter the name of a host computer or <enter> to finish: ");
host = Console.ReadLine();
if (host.Length > 0)
{
// Increment the request counter in a thread safe manner.
Interlocked.Increment(ref requestCounter);
// Start the asynchronous request for DNS information.
Dns.BeginGetHostEntry(host, callBack, host);
}
} while (host.Length > 0);
// The user has entered all of the host names for lookup.
// Now wait until the threads complete.
while (requestCounter > 0)
{
UpdateUserInterface();
}
// Display the results.
for (int i = 0; i< hostNames.Count; i++)
{
object data = hostData [i];
string message = data as string;
// A SocketException was thrown.
if (message != null)
{
Console.WriteLine("Request for {0} returned message: {1}",
hostNames[i], message);
continue;
}
// Get the results.
IPHostEntry h = (IPHostEntry) data;
string[] aliases = h.Aliases;
IPAddress[] addresses = h.AddressList;
if (aliases.Length > 0)
{
Console.WriteLine("Aliases for {0}", hostNames[i]);
for (int j = 0; j < aliases.Length; j++)
{
Console.WriteLine("{0}", aliases[j]);
}
}
if (addresses.Length > 0)
{
Console.WriteLine("Addresses for {0}", hostNames[i]);
for (int k = 0; k < addresses.Length; k++)
{
Console.WriteLine("{0}",addresses[k].ToString());
}
}
}
}
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Imports System.Collections.Specialized
Imports System.Collections
Namespace Examples.AdvancedProgramming.AsynchronousOperations
' The user has entered all of the host names for lookup.
' Now wait until the threads complete.
Do While requestCounter > 0
UpdateUserInterface()
Loop
' The following method is called when each asynchronous operation completes.
Shared Sub ProcessDnsInformation(result as IAsyncResult)
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Calling Asynchronous Methods Using IAsyncResult
Using an AsyncCallback Delegate and State Object
Using an AsyncCallback Delegate and State Object
7/29/2017 • 5 min to read • Edit Online
When you use an AsyncCallback delegate to process the results of the asynchronous operation in a separate
thread, you can use a state object to pass information between the callbacks and to retrieve a final result. This topic
demonstrates that practice by expanding the example in Using an AsyncCallback Delegate to End an Asynchronous
Operation.
Example
The following code example demonstrates using asynchronous methods in the Dns class to retrieve Domain Name
System (DNS) information for user-specified computers. This example defines and uses the HostRequest class to
store state information. A HostRequest object gets created for each computer name entered by the user. This
object is passed to the BeginGetHostByName method. The ProcessDnsInformation method is called each time a
request completes. The HostRequest object is retrieved using the AsyncState property. The ProcessDnsInformation
method uses the HostRequest object to store the IPHostEntry returned by the request or a SocketException thrown
by the request. When all requests are complete, the application iterates over the HostRequest objects and displays
the DNS information or SocketException error message.
/*
The following example demonstrates using asynchronous methods to
get Domain Name System information for the specified host computer.
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
// Create a state object that holds each requested host name,
// an associated IPHostEntry object or a SocketException.
public class HostRequest
{
// Stores the requested host name.
private string hostName;
// Stores any SocketException returned by the Dns EndGetHostByName method.
private SocketException e;
// Stores an IPHostEntry returned by the Dns EndGetHostByName method.
private IPHostEntry entry;
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Threading
Imports System.Collections
Namespace Examples.AdvancedProgramming.AsynchronousOperations
' Create a state object that holds each requested host name,
' an associated IPHostEntry object or a SocketException.
Public Class HostRequest
' Stores the requested host name.
Dim hostNameValue as string
' Stores any SocketException returned by the Dns EndGetHostByName method.
' Stores any SocketException returned by the Dns EndGetHostByName method.
Dim e as SocketException
' Stores an IPHostEntry returned by the Dns EndGetHostByName method.
Dim entry as IPHostEntry
Do
Console.Write(" Enter the name of a host computer or <enter> to finish: ")
host = Console.ReadLine()
If host.Length > 0
' Increment the request counter in a thread safe manner.
Interlocked.Increment (requestCounter)
' Create and store the state object for this request.
Dim request as HostRequest = new HostRequest(host)
hostData.Add(request)
' Start the asynchronous request for DNS information.
Dns.BeginGetHostEntry(host, callBack, request)
End If
Loop While host.Length > 0
' The user has entered all of the host names for lookup.
' Now wait until the threads complete.
Do While requestCounter > 0
UpdateUserInterface()
Loop
Loop
If aliases.Length > 0
Console.WriteLine("Aliases for {0}", r.HostName)
For j = 0 To aliases.Length - 1
Console.WriteLine("{0}", aliases(j))
Next j
End If
If addresses.Length > 0
Console.WriteLine("Addresses for {0}", r.HostName)
For k = 0 To addresses.Length -1
Console.WriteLine("{0}",addresses(k).ToString())
Next k
End If
End If
Next r
End Sub
' The following method is invoked when each asynchronous operation completes.
Shared Sub ProcessDnsInformation(result as IAsyncResult)
' Get the state object associated with this request.
Dim request as HostRequest= CType(result.AsyncState,HostRequest)
Try
' Get the results and store them in the state object.
Dim host as IPHostEntry = Dns.EndGetHostEntry(result)
request.HostEntry = host
Catch e as SocketException
' Store any SocketExceptions.
request.ExceptionObject = e
Finally
' Decrement the request counter in a thread-safe manner.
Interlocked.Decrement(requestCounter)
End Try
End Sub
End Class
End Namespace
See Also
Event-based Asynchronous Pattern (EAP)
Event-based Asynchronous Pattern Overview
Using an AsyncCallback Delegate to End an Asynchronous Operation
Asynchronous Programming Using Delegates
7/29/2017 • 1 min to read • Edit Online
Delegates enable you to call a synchronous method in an asynchronous manner. When you call a delegate
synchronously, the Invoke method calls the target method directly on the current thread. If the BeginInvoke
method is called, the common language runtime (CLR) queues the request and returns immediately to the caller.
The target method is called asynchronously on a thread from the thread pool. The original thread, which submitted
the request, is free to continue executing in parallel with the target method. If a callback method has been specified
in the call to the BeginInvoke method, the callback method is called when the target method ends. In the callback
method, the EndInvoke method obtains the return value and any input/output or output-only parameters. If no
callback method is specified when calling BeginInvoke , EndInvoke can be called from the thread that called
BeginInvoke .
IMPORTANT
Compilers should emit delegate classes with Invoke , BeginInvoke , and EndInvoke methods using the delegate signature
specified by the user. The BeginInvoke and EndInvoke methods should be decorated as native. Because these methods
are marked as native, the CLR automatically provides the implementation at class load time. The loader ensures that they are
not overridden.
In This Section
Calling Synchronous Methods Asynchronously
Discusses the use of delegates to make asynchronous calls to ordinary methods, and provides simple code
examples that show the four ways to wait for an asynchronous call to return.
Related Sections
Event-based Asynchronous Pattern (EAP)
Describes asynchronous programming with the .NET Framework.
See Also
Delegate
Calling Synchronous Methods Asynchronously
7/29/2017 • 18 min to read • Edit Online
The .NET Framework enables you to call any method asynchronously. To do this you define a delegate with the
same signature as the method you want to call; the common language runtime automatically defines BeginInvoke
and EndInvoke methods for this delegate, with the appropriate signatures.
NOTE
Asynchronous delegate calls, specifically the BeginInvoke and EndInvoke methods, are not supported in the .NET
Compact Framework.
The BeginInvoke method initiates the asynchronous call. It has the same parameters as the method that you want
to execute asynchronously, plus two additional optional parameters. The first parameter is an AsyncCallback
delegate that references a method to be called when the asynchronous call completes. The second parameter is a
user-defined object that passes information into the callback method. BeginInvoke returns immediately and does
not wait for the asynchronous call to complete. BeginInvoke returns an IAsyncResult, which can be used to monitor
the progress of the asynchronous call.
The EndInvoke method retrieves the results of the asynchronous call. It can be called any time after BeginInvoke . If
the asynchronous call has not completed, EndInvoke blocks the calling thread until it completes. The parameters of
EndInvoke include the out and ref parameters ( <Out> ByRef and ByRef in Visual Basic) of the method that
you want to execute asynchronously, plus the IAsyncResult returned by BeginInvoke .
NOTE
The IntelliSense feature in Visual Studio 2005 displays the parameters of BeginInvoke and EndInvoke . If you are not
using Visual Studio or a similar tool, or if you are using C# with Visual Studio 2005, see Asynchronous Programming Model
(APM) for a description of the parameters defined for these methods.
The code examples in this topic demonstrate four common ways to use BeginInvoke and EndInvoke to make
asynchronous calls. After calling BeginInvoke you can do the following:
Do some work and then call EndInvoke to block until the call completes.
Obtain a WaitHandle using the System.IAsyncResult.AsyncWaitHandle property, use its WaitOne method to
block execution until the WaitHandle is signaled, and then call EndInvoke .
Poll the IAsyncResult returned by BeginInvoke to determine when the asynchronous call has completed,
and then call EndInvoke .
Pass a delegate for a callback method to BeginInvoke . The method is executed on a ThreadPool thread when
the asynchronous call completes. The callback method calls EndInvoke .
IMPORTANT
No matter which technique you use, always call EndInvoke to complete your asynchronous call.
namespace Examples {
namespace AdvancedProgramming {
namespace AsynchronousOperations
{
public ref class AsyncDemo
{
public:
// The method to be executed asynchronously.
String^ TestMethod(int callDuration, [OutAttribute] int% threadId)
{
Console::WriteLine("Test method begins.");
Thread::Sleep(callDuration);
threadId = Thread::CurrentThread->ManagedThreadId;
return String::Format("My call time was {0}.", callDuration);
}
};
using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncDemo
{
// The method to be executed asynchronously.
public string TestMethod(int callDuration, out int threadId)
{
Console.WriteLine("Test method begins.");
Thread.Sleep(callDuration);
threadId = Thread.CurrentThread.ManagedThreadId;
return String.Format("My call time was {0}.", callDuration.ToString());
}
}
// The delegate must have the same signature as the method
// it will call asynchronously.
public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}
Imports System
Imports System.Threading
Imports System.Runtime.InteropServices
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncDemo
' The method to be executed asynchronously.
Public Function TestMethod(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
Console.WriteLine("Test method begins.")
Thread.Sleep(callDuration)
threadId = Thread.CurrentThread.ManagedThreadId()
return String.Format("My call time was {0}.", callDuration.ToString())
End Function
End Class
' The delegate must have the same signature as the method
' it will call asynchronously.
Public Delegate Function AsyncMethodCaller(ByVal callDuration As Integer, _
<Out> ByRef threadId As Integer) As String
End Namespace
IMPORTANT
Because EndInvoke might block, you should never call it from threads that service the user interface.
#using <TestMethod.dll>
void main()
{
// The asynchronous method puts the thread id here.
int threadId = 2546;
Thread::Sleep(1);
Console::WriteLine("Main thread {0} does some work.",
Thread::CurrentThread->ManagedThreadId);
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
public static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Public Class AsyncMain
Shared Sub Main()
' The asynchronous method puts the thread id here.
Dim threadId As Integer
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
End Namespace
NOTE
The wait handle is not closed automatically when you call EndInvoke . If you release all references to the wait handle, system
resources are freed when garbage collection reclaims the wait handle. To free the system resources as soon as you are
finished using the wait handle, dispose of it by calling the System.Threading.WaitHandle.Close method. Garbage collection
works more efficiently when disposable objects are explicitly disposed.
#using <TestMethod.dll>
void main()
{
// The asynchronous method puts the thread id here.
int threadId;
Thread::Sleep(0);
Console::WriteLine("Main thread {0} does some work.",
Thread::CurrentThread->ManagedThreadId);
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main()
{
// The asynchronous method puts the thread id here.
int threadId;
Thread.Sleep(0);
Console.WriteLine("Main thread {0} does some work.",
Thread.CurrentThread.ManagedThreadId);
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Thread.Sleep(0)
Console.WriteLine("Main thread {0} does some work.", _
Thread.CurrentThread.ManagedThreadId)
' Perform additional processing here and then
' wait for the WaitHandle to be signaled.
result.AsyncWaitHandle.WaitOne()
void main()
{
// The asynchronous method puts the thread id here.
int threadId;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main() {
// The asynchronous method puts the thread id here.
int threadId;
Namespace Examples.AdvancedProgramming.AsynchronousOperations
Console.WriteLine(vbCrLf & _
"The call executed on thread {0}, with return value ""{1}"".", _
threadId, returnValue)
End Sub
End Class
End Namespace
#using <TestMethod.dll>
void main()
{
// Create an instance of the test class.
AsyncDemo^ ad = gcnew AsyncDemo();
using System;
using System.Threading;
using System.Runtime.Remoting.Messaging;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
public class AsyncMain
{
static void Main()
{
// Create an instance of the test class.
AsyncDemo ad = new AsyncDemo();
Imports System
Imports System.Threading
Imports System.Runtime.Remoting.Messaging
Namespace Examples.AdvancedProgramming.AsynchronousOperations
' Initiate the asynchronous call, passing three seconds (3000 ms)
' for the callDuration parameter of TestMethod; a dummy variable
' for the <Out> parameter (threadId); the callback delegate; and
' state information that can be retrieved by the callback method.
' In this case, the state information is a string that can be used
' to format a console message.
Dim result As IAsyncResult = caller.BeginInvoke(3000, _
dummy, _
AddressOf CallbackMethod, _
"The call executed on thread {0}, with return value ""{1}"".")
' The callback method must have the same signature as the
' AsyncCallback delegate.
Shared Sub CallbackMethod(ByVal ar As IAsyncResult)
' Retrieve the delegate.
Dim result As AsyncResult = CType(ar, AsyncResult)
Dim caller As AsyncMethodCaller = CType(result.AsyncDelegate, AsyncMethodCaller)
See Also
Delegate
Event-based Asynchronous Pattern (EAP)