|
1 | | -# VSTHRD001 Avoid legacy thread switching methods |
2 | | - |
3 | | -Switching to the UI thread should be done using `JoinableTaskFactory.SwitchToMainThreadAsync` |
4 | | -rather than legacy methods such as `Dispatcher.Invoke` or `ThreadHelper.Invoke`. |
5 | | -This avoids deadlocks and can reduce threadpool starvation. |
6 | | - |
7 | | -## Examples of patterns that are flagged by this analyzer |
8 | | - |
9 | | -```csharp |
10 | | -ThreadHelper.Generic.Invoke(delegate { |
11 | | - DoSomething(); |
12 | | -}); |
13 | | -``` |
14 | | - |
15 | | -or |
16 | | - |
17 | | -```cs |
18 | | -Dispatcher.CurrentDispatcher.BeginInvoke(delegate { |
19 | | - DoSomething(); |
20 | | -}); |
21 | | -``` |
22 | | - |
23 | | -## Solution |
24 | | - |
25 | | -Use `await SwitchToMainThreadAsync()` instead, wrapping with the `JoinableTaskFactory`'s `Run` or `RunAsync` method if necessary: |
26 | | - |
27 | | -```csharp |
28 | | -void Foo() { |
29 | | - ThreadHelper.JoinableTaskFactory.Run(async delegate { |
30 | | - await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); |
31 | | - DoSomething(); |
32 | | - }); |
33 | | -} |
34 | | -``` |
35 | | - |
36 | | -In the above example, we obtain a `JoinableTaskFactory` instance from the `ThreadHelper.JoinableTaskFactory` static property |
37 | | -as it exists within Visual Studio itself. Other applications should create and expose their own `JoinableTaskContext` and/or `JoinableTaskFactory` for use in code that run in these applications. |
38 | | -See our doc on [consuming `JoinableTaskFactory` from a library](https://github.com/microsoft/vs-threading/blob/main/doc/library_with_jtf.md) for more information. |
39 | | - |
40 | | -### Replacing Dispatcher.BeginInvoke |
41 | | - |
42 | | -When updating calls to `Dispatcher.BeginInvoke`, there are a few considerations to consider. |
43 | | - |
44 | | -1. `BeginInvoke` schedules the delegate for execution later. |
45 | | -1. `BeginInvoke` always executes the delegate on the dispatcher's thread. |
46 | | -1. `BeginInvoke` schedules the delegate at some given priority, or default priority determined by the dispatcher. |
47 | | - |
48 | | -To resolve a warning for such code, it is often sufficient to replace it with this, which is *roughly* equivalent: |
49 | | - |
50 | | -```cs |
51 | | -await joinableTaskFactory.RunAsync(async delegate { |
52 | | - await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true); |
53 | | - DoSomething(); |
54 | | -}) |
55 | | -``` |
56 | | - |
57 | | -The first line in the delegate is necessary to match the behaviors of 1 and 2 on the above list. |
58 | | -When the caller is known to already be on the main thread, you can simplify it slightly to this: |
59 | | - |
60 | | -```cs |
61 | | -await joinableTaskFactory.RunAsync(async delegate { |
62 | | - await Task.Yield(); |
63 | | - DoSomething(); |
64 | | -}) |
65 | | -``` |
66 | | - |
67 | | -Matching behavior 3 on the list above may be important when the dispatcher priority is specified in the BeginInvoke call and was chosen for a particular reason. |
68 | | -In such a case, you can ensure that `JoinableTaskFactory` matches that priority instead of using its default by creating a special `JoinableTaskFactory` instance with the priority setting you require using the [`JoinableTaskFactory.WithPriority`](https://learn.microsoft.com/dotnet/api/microsoft.visualstudio.threading.dispatcherextensions.withpriority?view=visualstudiosdk-2022) method. |
69 | | - |
70 | | -Altogether, this might look like: |
71 | | - |
72 | | -```cs |
73 | | -await joinableTaskFactory.WithPriority(DispatcherPriority.DataBind).RunAsync(async delegate { |
74 | | - await joinableTaskFactory.SwitchToMainThreadAsync(alwaysYield: true); |
75 | | - DoSomething(); |
76 | | -}) |
77 | | -``` |
78 | | - |
79 | | -## Configuration |
80 | | - |
81 | | -This analyzer is configurable via the `vs-threading.LegacyThreadSwitchingMembers.txt` file. |
82 | | -See our [configuration](configuration.md) topic for more information. |
| 1 | +This content has been moved to [GitHub Pages](https://microsoft.github.io/vs-threading/analyzers/VSTHRD001.html). |
0 commit comments