Ensuring task execution order in threadpool

后端 未结 17 952
情深已故
情深已故 2020-12-12 11:54

I have been reading about the thread-pool pattern and I can\'t seem to find the usual solution for the following problem.

I sometimes want tasks to be executed serial

17条回答
  •  既然无缘
    2020-12-12 13:01

    Something like the following will allow serial and parallel tasks to be queued, where serial tasks will be executed one after the other, and parallel tasks will be executed in any order, but in parallel. This gives you the ability to serialize tasks where necessary, also have parallel tasks, but do this as tasks are received i.e. you do not need to know about the entire sequence up-front, execution order is maintained dynamically.

    internal class TaskQueue
    {
        private readonly object _syncObj = new object();
        private readonly Queue _tasks = new Queue();
        private int _runningTaskCount;
    
        public void Queue(bool isParallel, Action task)
        {
            lock (_syncObj)
            {
                _tasks.Enqueue(new QTask { IsParallel = isParallel, Task = task });
            }
    
            ProcessTaskQueue();
        }
    
        public int Count
        {
            get{lock (_syncObj){return _tasks.Count;}}
        }
    
        private void ProcessTaskQueue()
        {
            lock (_syncObj)
            {
                if (_runningTaskCount != 0) return;
    
                while (_tasks.Count > 0 && _tasks.Peek().IsParallel)
                {
                    QTask parallelTask = _tasks.Dequeue();
    
                    QueueUserWorkItem(parallelTask);
                }
    
                if (_tasks.Count > 0 && _runningTaskCount == 0)
                {
                    QTask serialTask = _tasks.Dequeue();
    
                    QueueUserWorkItem(serialTask);
                }
            }
        }
    
        private void QueueUserWorkItem(QTask qTask)
        {
            Action completionTask = () =>
            {
                qTask.Task();
    
                OnTaskCompleted();
            };
    
            _runningTaskCount++;
    
            ThreadPool.QueueUserWorkItem(_ => completionTask());
        }
    
        private void OnTaskCompleted()
        {
            lock (_syncObj)
            {
                if (--_runningTaskCount == 0)
                {
                    ProcessTaskQueue();
                }
            }
        }
    
        private class QTask
        {
            public Action Task { get; set; }
            public bool IsParallel { get; set; }
        }
    }
    

    Update

    To handle task groups with serial and parallel task mixes, a GroupedTaskQueue can manage a TaskQueue for each group. Again, you do not need to know about groups up-front, it is all dynamically managed as tasks are received.

    internal class GroupedTaskQueue
    {
        private readonly object _syncObj = new object();
        private readonly Dictionary _queues = new Dictionary();
        private readonly string _defaultGroup = Guid.NewGuid().ToString();
    
        public void Queue(bool isParallel, Action task)
        {
            Queue(_defaultGroup, isParallel, task);
        }
    
        public void Queue(string group, bool isParallel, Action task)
        {
            TaskQueue queue;
    
            lock (_syncObj)
            {
                if (!_queues.TryGetValue(group, out queue))
                {
                    queue = new TaskQueue();
    
                    _queues.Add(group, queue);
                }
            }
    
            Action completionTask = () =>
            {
                task();
    
                OnTaskCompleted(group, queue);
            };
    
            queue.Queue(isParallel, completionTask);
        }
    
        private void OnTaskCompleted(string group, TaskQueue queue)
        {
            lock (_syncObj)
            {
                if (queue.Count == 0)
                {
                    _queues.Remove(group);
                }
            }
        }
    }
    

提交回复
热议问题