示例#1
0
        /// <summary>
        /// The dispatcher logic
        /// </summary>
        private void OnDispatcherStart()
        {
            while (isRunning)
            {
                ProactorQueueData task = null;
                bool hasTask           = false;

                // do we have any completion task to finalise?
                SettleCompletedTasks();

                // do we have free threads?
                int threadIndex = GetNextAvailableThread();
                if (threadIndex < 0)
                {
                    // nope, let's wait until we have one
                    dispatcherSignal.WaitOne();
                    continue;
                }

                lock (taskQueueLock)
                    hasTask = taskQueue.TryDequeue(out task);

                if (!hasTask)
                {
                    // we can sleep the thread until a new task comes up
                    // but we can check again after 5 minutes in case the signal
                    // was never called
                    dispatcherSignal.WaitOne(TimeSpan.FromMinutes(5));
                    continue;
                }

                if (task == null)
                {
                    continue; // sanity check
                }
                // we can now dispatch this task over to the thread
                Log($"Dispatching task ({task.QueuedCode}) to thread {threadIndex}");
                workerThreads[threadIndex] = new Thread(WorkerThreadMethod)
                {
                    Name = $"WORKER-{threadIndex}"
                };

                task.ThreadIndex = threadIndex; // to keep track of the thread serving this task
                workerThreads[threadIndex].Start(task);
            }

            // ensure all threads are done
            for (int i = 0; i < WorkerCount; i++)
            {
                workerThreads[i]?.Join();
            }
            SettleCompletedTasks();
        }
示例#2
0
        /// <summary>
        /// Enqueues a function to the dispatcher queue
        /// </summary>
        public ProactorTask Enqueue(Func <object> resultFunction, Action <object> finishCallback = null)
        {
            ProactorQueueData data = new ProactorQueueData(resultFunction, finishCallback);

            Log($"Queueing a new task ({data.QueuedCode})");

            lock (taskQueueLock)
                taskQueue.Enqueue(data);

            // we can signal to the dispatcher thread to stop waiting for new tasks
            // and resume
            dispatcherSignal.Set();

            return(data.Task);
        }
示例#3
0
        private void SettleCompletedTasks()
        {
            lock (finishedQueueLock)
            {
                while (finishedQueue.Count > 0)
                {
                    ProactorQueueData finishedTask = finishedQueue.Dequeue();
                    Log($"Finishing task ({finishedTask.QueuedCode})");

                    // call the callback if not null
                    finishedTask.FinishCallback?.Invoke(finishedTask.Task.Result);

                    // free up the corresponding thread
                    int tid = finishedTask.ThreadIndex;
                    workerThreads[tid].Join();
                    workerThreads[tid] = null;

                    Log($"Freed thread {tid}");
                }
            }
        }
示例#4
0
        private void WorkerThreadMethod(object data)
        {
            Log($"Worker thread start");

            if (data == null && !(data is ProactorQueueData))
            {
                throw new ArgumentException($"{nameof(data)} must be of {nameof(ProactorQueueData)} type");
            }

            ProactorQueueData task   = (ProactorQueueData)data;
            object            result = task.Operation();

            task.Task.Finished = true;
            task.Task.Result   = result;

            // we have something to run on completion, on the dispatcher thread, so we queue it
            // and signal the dispatcher
            lock (finishedQueueLock)
                finishedQueue.Enqueue(task);

            dispatcherSignal.Set();
        }