annotate Implab/Parallels/WorkerPool.cs @ 12:eb418ba8275b promises

refactoring, added WorkerPool
author cin
date Tue, 05 Nov 2013 19:55:34 +0400
parents
children b0feb5b9ad1c
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
12
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
1 using System;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
2 using System.Collections.Generic;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
3 using System.Linq;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
4 using System.Text;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
5 using System.Threading;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
6 using System.Diagnostics;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
7
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
8 namespace Implab.Parallels {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
9 public class WorkerPool : IDisposable {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
10 readonly int m_minThreads;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
11 readonly int m_maxThreads;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
12 int m_runningThreads;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
13 object m_lock = new object();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
14
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
15 bool m_disposed = false;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
16 ManualResetEvent m_hasTasks = new ManualResetEvent(false);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
17 Queue<Action> m_queue = new Queue<Action>();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
18
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
19 public WorkerPool(int min, int max) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
20 if (min < 0)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
21 throw new ArgumentOutOfRangeException("min");
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
22 if (min > max)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
23 min = max;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
24 m_minThreads = min;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
25 m_maxThreads = max;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
26
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
27 for (int i = 0; i < m_minThreads; i++)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
28 StartWorker();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
29 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
30
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
31 public Promise<T> Invoke<T>(Func<T> task) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
32 if (m_disposed)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
33 throw new ObjectDisposedException(ToString());
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
34 if (task == null)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
35 throw new ArgumentNullException("task");
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
36
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
37 var promise = new Promise<T>();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
38
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
39
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
40
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
41 return promise;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
42 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
43
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
44 bool StartWorker() {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
45 var current = m_runningThreads;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
46 // use spins to allocate slot for the new thread
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
47 do {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
48 if (current >= m_maxThreads)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
49 // no more slots left
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
50 return false;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
51 } while (current != Interlocked.CompareExchange(ref m_runningThreads, current + 1, current));
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
52
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
53 // slot successfully allocated
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
54
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
55 var worker = new Thread(this.Worker);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
56 worker.Start();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
57
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
58 return true;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
59 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
60
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
61 void EnqueueTask(Action task) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
62 Debug.Assert(task != null);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
63 lock (m_queue) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
64 m_queue.Enqueue(task);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
65 m_hasTasks.Set();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
66 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
67 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
68
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
69 bool FetchTask(out Action task) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
70 task = null;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
71
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
72 while (true) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
73
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
74 m_hasTasks.WaitOne();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
75
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
76 if (m_disposed)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
77 return false;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
78
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
79 lock (m_queue) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
80 if (m_queue.Count > 0) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
81 task = m_queue.Dequeue();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
82 return true;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
83 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
84
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
85 // no tasks left
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
86 // signal that no more tasks left, lock ensures that this event won't suppress newly added task
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
87 m_hasTasks.Reset();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
88 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
89
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
90 bool exit = true;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
91
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
92 var current = m_runningThreads;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
93 do {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
94 if (current <= m_minThreads) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
95 exit = false; // this thread should return and wait for the new events
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
96 break;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
97 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
98 } while (current != Interlocked.CompareExchange(ref m_runningThreads, current - 1, current));
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
99
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
100 if (exit)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
101 return false;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
102 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
103 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
104
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
105 void Worker() {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
106 Action task;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
107 while (FetchTask(out task))
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
108 task();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
109 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
110
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
111 protected virtual void Dispose(bool disposing) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
112 if (disposing) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
113 lock (m_lock) {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
114 if (m_disposed)
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
115 return;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
116 m_disposed = true;
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
117 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
118 m_hasTasks.Set();
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
119 GC.SuppressFinalize(this);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
120 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
121 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
122
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
123 public void Dispose() {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
124 Dispose(true);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
125 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
126
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
127 ~WorkerPool() {
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
128 Dispose(false);
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
129 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
130 }
eb418ba8275b refactoring, added WorkerPool
cin
parents:
diff changeset
131 }