/
WorkerThread.cs
130 lines (111 loc) · 4.1 KB
/
WorkerThread.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
#if XBOX
namespace System.Threading {
public enum ThreadPriority {
// Summary:
// The System.Threading.Thread can be scheduled after threads with any other
// priority.
Lowest = 0,
//
// Summary:
// The System.Threading.Thread can be scheduled after threads with Normal priority
// and before those with Lowest priority.
BelowNormal = 1,
//
// Summary:
// The System.Threading.Thread can be scheduled after threads with AboveNormal
// priority and before those with BelowNormal priority. Threads have Normal
// priority by default.
Normal = 2,
//
// Summary:
// The System.Threading.Thread can be scheduled after threads with Highest priority
// and before those with Normal priority.
AboveNormal = 3,
//
// Summary:
// The System.Threading.Thread can be scheduled before threads with any other
// priority.
Highest = 4,
}
}
#endif
namespace Squared.Task.Internal {
public delegate void WorkerThreadFunc<in T> (T workItems, ManualResetEvent newWorkItemEvent);
public class WorkerThread<Container> : IDisposable
where Container : new() {
private WorkerThreadFunc<Container> _ThreadFunc;
private Thread _Thread = null;
private ManualResetEvent _WakeEvent = new ManualResetEvent(false);
private Container _WorkItems = new Container();
private ThreadPriority _Priority;
private bool _IsDisposed = false;
public WorkerThread (WorkerThreadFunc<Container> threadFunc, ThreadPriority priority) {
_ThreadFunc = threadFunc;
_Priority = priority;
}
public Container WorkItems {
get {
return _WorkItems;
}
}
public void Wake () {
if (_IsDisposed)
return;
if (_WakeEvent != null)
_WakeEvent.Set();
if (_Thread == null) {
var newThread = new Thread(() => {
try {
var wi = _WorkItems;
var we = _WakeEvent;
// If either of these fields are null, we've probably been disposed
if ((wi != null) && (we != null))
_ThreadFunc(wi, we);
#if !XBOX
} catch (ThreadInterruptedException) {
#endif
} catch (ThreadAbortException) {
}
var me = Interlocked.Exchange(ref _Thread, null);
if (me == Thread.CurrentThread)
OnThreadTerminated(Thread.CurrentThread);
});
#if !XBOX
newThread.Priority = _Priority;
#endif
newThread.IsBackground = true;
newThread.Name = String.Format("{0}_{1}", _ThreadFunc.ToString(), this.GetHashCode());
if (Interlocked.CompareExchange(ref _Thread, newThread, null) == null)
newThread.Start();
}
}
private void OnThreadTerminated (Thread theThread) {
if (_IsDisposed)
return;
var we = _WakeEvent;
if ((we != null) && we.WaitOne(1))
Wake();
}
public void Dispose () {
if (_IsDisposed)
return;
_IsDisposed = true;
Thread.MemoryBarrier();
var wakeEvent = Interlocked.Exchange(ref _WakeEvent, null);
var thread = Interlocked.Exchange(ref _Thread, null);
if (thread != null) {
#if !XBOX
thread.Interrupt();
#else
thread.Abort();
#endif
}
if (wakeEvent != null)
wakeEvent.Set();
}
}
}