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

Commit 328a0f1

Browse files
committed
More on thread management
1 parent afa3958 commit 328a0f1

File tree

7 files changed

+81
-34
lines changed

7 files changed

+81
-34
lines changed

Toastify/src/App.xaml.cs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Windows;
1313
using System.Windows.Input;
1414
using System.Windows.Threading;
15+
using Aleab.Common.Extensions;
1516
using Castle.MicroKernel.Registration;
1617
using Castle.Windsor;
1718
using JetBrains.Annotations;

Toastify/src/Core/Auth/ToastifyWebAuth.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ protected override void Authorize()
7777

7878
public override Task<IToken> GetToken()
7979
{
80-
return this.authHttpServer == null ? null : base.GetToken();
80+
return this.authHttpServer == null ? Task.FromResult((IToken)null) : base.GetToken();
8181
}
8282

8383
protected override IToken CreateToken(SpotifyTokenResponse spotifyTokenResponse)

Toastify/src/Threading/ThreadManager.cs

+38-21
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,23 @@ public void Add(Thread thread)
7171
{
7272
if (thread == null)
7373
return;
74-
this.threads.Remove(thread);
75-
this.threads.Add(thread);
74+
75+
lock (instanceLock)
76+
{
77+
this.threads.Remove(thread);
78+
this.threads.Add(thread);
79+
}
7680
}
7781

7882
public void Remove(Thread thread)
7983
{
8084
if (thread == null)
8185
return;
82-
this.threads.Remove(thread);
86+
87+
lock (instanceLock)
88+
{
89+
this.threads.Remove(thread);
90+
}
8391
}
8492

8593
public void Abort(Thread thread)
@@ -94,9 +102,12 @@ private void Abort(Thread thread, bool remove)
94102

95103
try
96104
{
97-
if (remove)
98-
this.Remove(thread);
99-
thread.Abort();
105+
lock (instanceLock)
106+
{
107+
if (remove)
108+
this.Remove(thread);
109+
thread.Abort();
110+
}
100111
}
101112
catch
102113
{
@@ -110,16 +121,19 @@ private void DeadThreadsCleanerThreadStart()
110121
{
111122
while (!App.ShutdownEvent.WaitOne(TimeSpan.FromSeconds(10)))
112123
{
113-
List<Thread> threadsToRemove = new List<Thread>(this.threads.Count);
114-
foreach (var thread in this.threads)
115-
{
116-
if (!thread.IsAlive)
117-
threadsToRemove.Add(thread);
118-
}
119-
120-
foreach (var thread in threadsToRemove)
124+
lock (instanceLock)
121125
{
122-
this.Remove(thread);
126+
List<Thread> threadsToRemove = new List<Thread>(this.threads.Count);
127+
foreach (var thread in this.threads)
128+
{
129+
if (!thread.IsAlive)
130+
threadsToRemove.Add(thread);
131+
}
132+
133+
foreach (var thread in threadsToRemove)
134+
{
135+
this.Remove(thread);
136+
}
123137
}
124138
}
125139
}
@@ -131,17 +145,20 @@ private void DeadThreadsCleanerThreadStart()
131145

132146
public void Dispose()
133147
{
134-
if (this.threads != null)
148+
lock (instanceLock)
135149
{
136-
foreach (var thread in this.threads)
150+
if (this.threads != null)
137151
{
138-
this.Abort(thread, false);
152+
foreach (var thread in this.threads)
153+
{
154+
this.Abort(thread, false);
155+
}
156+
157+
this.threads.Clear();
139158
}
140159

141-
this.threads.Clear();
160+
this.Abort(this.deadThreadsCleaner, false);
142161
}
143-
144-
this.Abort(this.deadThreadsCleaner, false);
145162
}
146163

147164
#region Static Members

Toastify/src/Threading/WindowThread.cs

+27-9
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace Toastify.Threading
1616

1717
public T Window { get; private set; }
1818

19-
public Thread Thread { get; }
19+
public Thread Thread { get; private set; }
2020

2121
public bool IsBackground
2222
{
@@ -65,6 +65,7 @@ public void Start()
6565
public void Abort()
6666
{
6767
ThreadManager.Instance.Abort(this.Thread);
68+
this.Thread = null;
6869
}
6970

7071
public void Join()
@@ -101,25 +102,41 @@ public void CloseWindow()
101102
}
102103
catch (Exception ex)
103104
{
104-
logger.Error($"Unhandled error while closing {nameof(WindowThread<T>)}'s window{(!string.IsNullOrWhiteSpace(this.Window?.Title) ? $" ({this.Window.Title})" : string.Empty)}", ex);
105+
if (this.Window != null)
106+
{
107+
this.Window.Dispatcher.Invoke(DispatcherPriority.Normal, new ThreadStart(() =>
108+
{
109+
string title = !string.IsNullOrWhiteSpace(this.Window?.Title) ? $" ({this.Window.Title})" : string.Empty;
110+
logger.Error($"Unhandled error while closing {nameof(WindowThread<T>)}'s window{title}", ex);
111+
}));
112+
}
113+
else
114+
logger.Error($"Unhandled error while closing {nameof(WindowThread<T>)}'s window", ex);
105115
}
106116
}
107117

108118
private void ThreadStart()
109119
{
120+
var syncContext = SynchronizationContext.Current;
121+
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
122+
110123
try
111124
{
112-
var syncContext = SynchronizationContext.Current;
113-
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
114-
115125
this.Window = new T();
116126
this.options?.WindowInitialization?.Invoke(this.Window);
117127

118128
this.Window.Closed += (sender, args) =>
119129
{
120-
Application.Current?.Dispatcher?.BeginInvoke(new Action(() => Application.Current.Exit -= this.Application_Exit));
121-
this.options?.OnWindowClosingAction?.Invoke(this);
122-
this.Window?.Dispatcher?.BeginInvokeShutdown(DispatcherPriority.Background);
130+
try
131+
{
132+
Application.Current?.Dispatcher?.BeginInvoke(new Action(() => Application.Current.Exit -= this.Application_Exit));
133+
this.options?.OnWindowClosingAction?.Invoke(this);
134+
this.Window?.Dispatcher?.BeginInvokeShutdown(DispatcherPriority.Background);
135+
}
136+
catch
137+
{
138+
// ignore
139+
}
123140
};
124141
Application.Current?.Dispatcher?.Invoke(() => Application.Current.Exit += this.Application_Exit);
125142

@@ -128,7 +145,6 @@ private void ThreadStart()
128145
this.options?.AfterWindowShownAction?.Invoke(this.Window);
129146

130147
Dispatcher.Run();
131-
SynchronizationContext.SetSynchronizationContext(syncContext);
132148
}
133149
catch (ThreadAbortException)
134150
{
@@ -141,11 +157,13 @@ private void ThreadStart()
141157
{
142158
this.CloseWindow();
143159
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
160+
SynchronizationContext.SetSynchronizationContext(syncContext);
144161
}
145162
}
146163

147164
public override int GetHashCode()
148165
{
166+
// ReSharper disable once NonReadonlyMemberInGetHashCode
149167
return this.Thread?.GetHashCode() ?? 0;
150168
}
151169

Toastify/src/View/WebView.xaml.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,15 @@ private string GetAdditionalHeaders(Dictionary<string, string> additionalHeaders
8484

8585
private void WebView_OnClosing(object sender, EventArgs e)
8686
{
87-
this.WebBrowser.Dispatcher.InvokeShutdown();
88-
this.WebBrowser.Dispose();
87+
try
88+
{
89+
this.WebBrowser.Dispatcher.InvokeShutdown();
90+
this.WebBrowser.Dispose();
91+
}
92+
catch
93+
{
94+
// ignore
95+
}
8996
}
9097

9198
private void WebBrowser_OnLoadCompleted(object sender, NavigationEventArgs e)

ToastifyAPI/Core/Auth/ToastifyWebAuthAPI/BaseSpotifyWebAuth.cs

+4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ public virtual async Task<IToken> GetToken()
4646
}
4747

4848
if (shouldAbortAuthorization)
49+
{
50+
this.AuthHttpServer.AuthorizationFinished -= this.AuthHttpServer_AuthorizationFinished;
51+
await this.AuthHttpServer.Stop().ConfigureAwait(false);
4952
return null;
53+
}
5054

5155
if (this.authResponse.Error == null && !string.IsNullOrWhiteSpace(this.authResponse.Code))
5256
{

0 commit comments

Comments
 (0)