Skip to content
This repository was archived by the owner on Jun 21, 2023. It is now read-only.

Commit dda94d2

Browse files
committed
Flesh out the threading helper code
1 parent c4aad9a commit dda94d2

File tree

2 files changed

+122
-3
lines changed

2 files changed

+122
-3
lines changed
446 Bytes
Binary file not shown.
Lines changed: 122 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,134 @@
11
using System.Threading.Tasks;
22
using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper;
33
using GitHub.Extensions;
4+
using System.Runtime.CompilerServices;
5+
using System;
6+
using static Microsoft.VisualStudio.Threading.JoinableTaskFactory;
7+
using System.Threading;
48

59
namespace GitHub.Helpers
610
{
11+
public interface IAwaitable
12+
{
13+
IAwaiter GetAwaiter();
14+
}
15+
16+
public interface IAwaiter : INotifyCompletion
17+
{
18+
bool IsCompleted { get; }
19+
void GetResult();
20+
}
21+
722
public static class ThreadingHelper
823
{
9-
public async static Task SwitchToMainThreadAsync()
24+
/// <summary>
25+
/// Switch to the UI thread using ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync
26+
/// Auto-disables switching when running in unit test mode
27+
/// </summary>
28+
/// <returns></returns>
29+
public static IAwaitable SwitchToMainThreadAsync()
30+
{
31+
return Guard.InUnitTestRunner() ?
32+
new AwaitableWrapper() :
33+
new AwaitableWrapper(ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync());
34+
}
35+
36+
/// <summary>
37+
/// Switch to a thread pool background thread if the current thread isn't one, otherwise does nothing
38+
/// Auto-disables switching when running in unit test mode
39+
/// </summary>
40+
/// <param name="scheduler"></param>
41+
/// <returns></returns>
42+
public static IAwaitable SwitchToPoolThreadAsync(TaskScheduler scheduler)
43+
{
44+
return Guard.InUnitTestRunner() ?
45+
new AwaitableWrapper() :
46+
new AwaitableWrapper(scheduler);
47+
}
48+
49+
class AwaitableWrapper : IAwaitable
50+
{
51+
Func<IAwaiter> getAwaiter;
52+
53+
public AwaitableWrapper()
54+
{
55+
getAwaiter = () => new AwaiterWrapper();
56+
}
57+
58+
public AwaitableWrapper(MainThreadAwaitable awaitable)
59+
{
60+
getAwaiter = () => new AwaiterWrapper(awaitable.GetAwaiter());
61+
}
62+
63+
public AwaitableWrapper(TaskScheduler scheduler)
64+
{
65+
getAwaiter = () => new AwaiterWrapper(new BackgroundThreadAwaiter(scheduler));
66+
}
67+
68+
public IAwaiter GetAwaiter() => getAwaiter();
69+
}
70+
71+
class AwaiterWrapper : IAwaiter
72+
{
73+
Func<bool> isCompleted;
74+
Action<Action> onCompleted;
75+
Action getResult;
76+
77+
public AwaiterWrapper()
78+
{
79+
isCompleted = () => true;
80+
onCompleted = c => c();
81+
getResult = () => {};
82+
}
83+
84+
public AwaiterWrapper(MainThreadAwaiter awaiter)
85+
{
86+
isCompleted = () => awaiter.IsCompleted;
87+
onCompleted = c => awaiter.OnCompleted(c);
88+
getResult = () => awaiter.GetResult();
89+
}
90+
91+
public AwaiterWrapper(BackgroundThreadAwaiter awaiter)
92+
{
93+
isCompleted = () => awaiter.IsCompleted;
94+
onCompleted = c => awaiter.OnCompleted(c);
95+
getResult = () => awaiter.GetResult();
96+
}
97+
98+
public bool IsCompleted => isCompleted();
99+
100+
public void OnCompleted(Action continuation) => onCompleted(continuation);
101+
102+
public void GetResult() => getResult();
103+
}
104+
105+
struct BackgroundThreadAwaiter : INotifyCompletion
10106
{
11-
if (!Guard.InUnitTestRunner())
12-
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
107+
readonly TaskScheduler scheduler;
108+
109+
public bool IsCompleted
110+
{
111+
get
112+
{
113+
bool isThreadPoolThread = Thread.CurrentThread.IsThreadPoolThread;
114+
return (scheduler == TaskScheduler.Default & isThreadPoolThread) || (scheduler == TaskScheduler.Current && TaskScheduler.Current != TaskScheduler.Default);
115+
}
116+
}
117+
118+
public BackgroundThreadAwaiter(TaskScheduler scheduler)
119+
{
120+
Guard.ArgumentNotNull(scheduler, nameof(scheduler));
121+
this.scheduler = scheduler;
122+
}
123+
124+
public void OnCompleted(Action continuation)
125+
{
126+
Task.Factory.StartNew(continuation, CancellationToken.None, TaskCreationOptions.None, scheduler);
127+
}
128+
129+
public void GetResult()
130+
{
131+
}
13132
}
14133
}
15134
}

0 commit comments

Comments
 (0)