main
  1using System;
  2using System.Collections;
  3using System.ComponentModel;
  4using System.Diagnostics;
  5using System.Security.Permissions;
  6using System.Threading;
  7
  8namespace momoney.service.infrastructure.threading
  9{
 10    [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
 11    public class Synchronizer : ISynchronizeInvoke, IDisposable
 12    {
 13        readonly WorkerThread worker_thread;
 14
 15        public Synchronizer()
 16        {
 17            worker_thread = new WorkerThread(this);
 18        }
 19
 20        public bool InvokeRequired
 21        {
 22            get { return ReferenceEquals(Thread.CurrentThread, worker_thread); }
 23        }
 24
 25        public IAsyncResult BeginInvoke(Delegate method, object[] args)
 26        {
 27            var result = new WorkItem(null, method, args);
 28            worker_thread.queue_work_item(result);
 29            return result;
 30        }
 31
 32        public object EndInvoke(IAsyncResult result)
 33        {
 34            result.AsyncWaitHandle.WaitOne();
 35            return ((WorkItem) result).MethodReturnedValue;
 36        }
 37
 38        public object Invoke(Delegate method, object[] args)
 39        {
 40            return EndInvoke(BeginInvoke(method, args));
 41        }
 42
 43        ~Synchronizer()
 44        {
 45        }
 46
 47        public void Dispose()
 48        {
 49            worker_thread.kill();
 50        }
 51
 52        class WorkerThread
 53        {
 54            Thread thread;
 55            bool end_loop;
 56            readonly Mutex end_loop_mutex;
 57            readonly AutoResetEvent item_added;
 58            Synchronizer synchronizer;
 59            readonly Queue work_item_queue;
 60
 61            internal WorkerThread(Synchronizer synchronizer)
 62            {
 63                this.synchronizer = synchronizer;
 64                end_loop = false;
 65                thread = null;
 66                end_loop_mutex = new Mutex();
 67                item_added = new AutoResetEvent(false);
 68                work_item_queue = new Queue();
 69                create_thread(true);
 70            }
 71
 72            internal void queue_work_item(WorkItem work_item)
 73            {
 74                lock (work_item_queue.SyncRoot)
 75                {
 76                    work_item_queue.Enqueue(work_item);
 77                    item_added.Set();
 78                }
 79            }
 80
 81            bool EndLoop
 82            {
 83                set
 84                {
 85                    end_loop_mutex.WaitOne();
 86                    end_loop = value;
 87                    end_loop_mutex.ReleaseMutex();
 88                }
 89                get
 90                {
 91                    var result = false;
 92                    end_loop_mutex.WaitOne();
 93                    result = end_loop;
 94                    end_loop_mutex.ReleaseMutex();
 95                    return result;
 96                }
 97            }
 98
 99            Thread create_thread(bool auto_start)
100            {
101                if (thread != null)
102                {
103                    Debug.Assert(false);
104                    return thread;
105                }
106                thread = new Thread(run) {Name = "Synchronizer Worker Thread"};
107                if (auto_start)
108                {
109                    thread.Start();
110                }
111                return thread;
112            }
113
114            void start()
115            {
116                Debug.Assert(thread != null);
117                Debug.Assert(thread.IsAlive == false);
118                thread.Start();
119            }
120
121            bool queue_empty
122            {
123                get
124                {
125                    lock (work_item_queue.SyncRoot)
126                    {
127                        if (work_item_queue.Count > 0)
128                        {
129                            return false;
130                        }
131                        return true;
132                    }
133                }
134            }
135
136            WorkItem GetNext()
137            {
138                if (queue_empty)
139                {
140                    return null;
141                }
142                lock (work_item_queue.SyncRoot)
143                {
144                    return (WorkItem) work_item_queue.Dequeue();
145                }
146            }
147
148            void run()
149            {
150                while (EndLoop == false)
151                {
152                    while (queue_empty == false)
153                    {
154                        if (EndLoop)
155                        {
156                            return;
157                        }
158                        var workItem = GetNext();
159                        workItem.CallBack();
160                    }
161                    item_added.WaitOne();
162                }
163            }
164
165            public void kill()
166            {
167                //Kill is called on client thread - must use cached thread object
168                Debug.Assert(thread != null);
169                if (thread.IsAlive == false)
170                {
171                    return;
172                }
173                EndLoop = true;
174                item_added.Set();
175
176                //Wait for thread to die
177                thread.Join();
178                if (end_loop_mutex != null)
179                {
180                    end_loop_mutex.Close();
181                }
182                if (item_added != null)
183                {
184                    item_added.Close();
185                }
186            }
187        }
188    }
189}