Ik ben even flink bezig geweest met multi threading in .Net 2.0 & C# en nu zoek ik een manier om mijn applicatie netjes te sluiten (dus niet bruut alle threads killen terwijl ze nog bezig zijn), en heb dat met een Destructor willen oplossen, zie onderstaande voorbeeld code:
Thread.cs
RequestManager.cs
IConsoleWritingRequestManager.cs
ConsoleeApplication1.cs
Probleem is dat de Program destructor niet wordt uitgevoerd, waardoor de ConsoleWritingRequestManager private static instance een verwijzing houdt waardoor de thread actief blijft en niet wordt opgeruimd, gevolg: applicatie sluit niet netjes. Nu zou ik natuurlijk de Release() kunnen uitvoeren na de Go() of in de Go(), maar dat vind ik een niet zo nette oplossing. Vraag is nu hoe ik kan zorgen dat de destructor wordt aangeroepen.
Thread.cs
C#:
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
| public abstract class Thread { private System.Threading.Thread workerThread; private System.Threading.AutoResetEvent autoResetEvents; private bool suspended; public Thread(System.Threading.ThreadPriority ThreadPriority) { workerThread = new System.Threading.Thread(new System.Threading.ThreadStart(Execute)); autoResetEvents = new System.Threading.AutoResetEvent(false); workerThread.Priority = ThreadPriority; suspended = true; } public void Suspend() { suspended = true; this.Signal(); workerThread.Join(); } public void Resume() { try { suspended = false; workerThread.Start(); } catch (System.Threading.ThreadStartException tse) { suspended = true; throw tse; } } protected virtual void Execute() { while (workerThread.IsAlive) { ExecuteTask(); autoResetEvents.WaitOne(); if (suspended) break; } } protected abstract void ExecuteTask(); protected void Signal() { autoResetEvents.Set(); } } |
RequestManager.cs
C#:
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
| public interface IRequest { } public abstract class RequestManager : Thread { private System.Collections.Generic.Queue<IRequest> requestQueue; public RequestManager(System.Threading.ThreadPriority ThreadPriority) : base(ThreadPriority) { requestQueue = new System.Collections.Generic.Queue<IRequest>(); this.Resume(); } ~RequestManager() { this.Suspend(); } protected override void ExecuteTask() { lock(requestQueue) while (requestQueue.Count > 0) ProcessRequest(requestQueue.Dequeue()); } protected abstract void ProcessRequest(IRequest Request); public void AddRequest(IRequest Request) { lock(requestQueue) requestQueue.Enqueue(Request); this.Signal(); } } |
IConsoleWritingRequestManager.cs
C#:
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
| public interface IConsoleWritingRequest : IRequest { string Text { get; } } public class ConsoleWritingRequest : IConsoleWritingRequest { private string text; public string Text { get { return text; } } public ConsoleWritingRequest(string text) { this.text = text; } } public sealed class ConsoleWritingRequestManager : RequestManager { private static ConsoleWritingRequestManager instance = null; public static ConsoleWritingRequestManager Instance { get { if(instance == null) instance = new ConsoleWritingRequestManager(); return instance; } } private ConsoleWritingRequestManager() : base(System.Threading.ThreadPriority.BelowNormal) { } protected override void ProcessRequest(IRequest Request) { if (Request is IConsoleWritingRequest) { IConsoleWritingRequest ConsoleWritingRequest = (Request as IConsoleWritingRequest); System.Console.WriteLine(ConsoleWritingRequest.Text); } } public void Release() { instance = null; } } |
ConsoleeApplication1.cs
C#:
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
| namespace ConsoleApplication1 { public class Program { private ConsoleWritingRequestManager ConsoleWritingRequestManager; public Program() { this.ConsoleWritingRequestManager = ConsoleWritingRequestManager.Instance; } ~Program() { this.ConsoleWritingRequestManager.Release(); } public void Go() { this.ConsoleWritingRequestManager.AddRequest(new ConsoleWritingRequest("Hello world!")); } static void Main(string[] args) { new Program().Go(); } } } |
Probleem is dat de Program destructor niet wordt uitgevoerd, waardoor de ConsoleWritingRequestManager private static instance een verwijzing houdt waardoor de thread actief blijft en niet wordt opgeruimd, gevolg: applicatie sluit niet netjes. Nu zou ik natuurlijk de Release() kunnen uitvoeren na de Go() of in de Go(), maar dat vind ik een niet zo nette oplossing. Vraag is nu hoe ik kan zorgen dat de destructor wordt aangeroepen.