-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
Copy pathSyncAsyncEventArgs.cs
94 lines (90 loc) · 4.14 KB
/
SyncAsyncEventArgs.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using System.Threading;
namespace Azure
{
/// <summary>
/// Provides data for <see cref="Azure.Core.SyncAsyncEventHandler{T}"/>
/// events that can be invoked either synchronously or asynchronously.
/// </summary>
public class SyncAsyncEventArgs : EventArgs
{
/// <summary>
/// Gets a value indicating whether the event handler was invoked
/// synchronously or asynchronously. Please see
/// <see cref="Azure.Core.SyncAsyncEventHandler{T}"/> for more details.
/// </summary>
/// <remarks>
/// <para>
/// The same <see cref="Azure.Core.SyncAsyncEventHandler{T}"/>
/// event can be raised from both synchronous and asynchronous code
/// paths depending on whether you're calling sync or async methods on
/// a client. If you write an async handler but raise it from a sync
/// method, the handler will be doing sync-over-async and may cause
/// ThreadPool starvation. See
/// <see href="https://docs.microsoft.com/archive/blogs/vancem/diagnosing-net-core-threadpool-starvation-with-perfview-why-my-service-is-not-saturating-all-cores-or-seems-to-stall">
/// Diagnosing .NET Core ThreadPool Starvation with PerfView</see> for
/// a detailed explanation of how that can cause ThreadPool starvation
/// and serious performance problems.
/// </para>
/// <para>
/// You can use this <see cref="RunSynchronously"/> property to check
/// how the event is being raised and implement your handler
/// accordingly. Here's an example handler that's safe to invoke from
/// both sync and async code paths.
/// <code snippet="Snippet:Azure_Core_Samples_EventSamples_CombinedHandler">
/// var client = new AlarmClient();
/// client.Ring += async (SyncAsyncEventArgs e) =>
/// {
/// if (e.RunSynchronously)
/// {
/// Console.WriteLine("Wake up!");
/// }
/// else
/// {
/// await Console.Out.WriteLineAsync("Wake up!");
/// }
/// };
///
/// client.Snooze(); // sync call that blocks
/// await client.SnoozeAsync(); // async call that doesn't block
/// </code>
/// </para>
/// </remarks>
public bool RunSynchronously { get; }
/// <summary>
/// Gets a cancellation token related to the original operation that
/// raised the event. It's important for your handler to pass this
/// token along to any asynchronous or long-running synchronous
/// operations that take a token so cancellation (via something like
/// <code>
/// new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token
/// </code>
/// for example) will correctly propagate.
/// </summary>
public CancellationToken CancellationToken { get; }
/// <summary>
/// Initializes a new instance of the <see cref="SyncAsyncEventArgs"/>
/// class.
/// </summary>
/// <param name="runSynchronously">
/// A value indicating whether the event handler was invoked
/// synchronously or asynchronously. Please see
/// <see cref="Azure.Core.SyncAsyncEventHandler{T}"/> for more details.
/// </param>
/// <param name="cancellationToken">
/// A cancellation token related to the original operation that raised
/// the event. It's important for your handler to pass this token
/// along to any asynchronous or long-running synchronous operations
/// that take a token so cancellation will correctly propagate. The
/// default value is <see cref="CancellationToken.None"/>.
/// </param>
public SyncAsyncEventArgs(bool runSynchronously, CancellationToken cancellationToken = default)
: base()
{
RunSynchronously = runSynchronously;
CancellationToken = cancellationToken;
}
}
}