// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Tools.DotNETCommon { /// /// Allows queuing a large number of tasks to a thread pool and waiting for them all to complete. /// public class ThreadPoolWorkQueue : IDisposable { /// /// Number of jobs remaining in the queue. This is updated in an atomic way. /// int NumOutstandingJobs; /// /// Event which indicates whether the queue is empty. /// ManualResetEvent EmptyEvent = new ManualResetEvent(true); /// /// Default constructor /// public ThreadPoolWorkQueue() { } /// /// Waits for the queue to drain, and disposes of it /// public void Dispose() { if(EmptyEvent != null) { Wait(); EmptyEvent.Dispose(); EmptyEvent = null; } } /// /// Returns the number of items remaining in the queue /// public int NumRemaining { get { return NumOutstandingJobs; } } /// /// Adds an item to the queue /// /// The action to add public void Enqueue(Action ActionToExecute) { if(Interlocked.Increment(ref NumOutstandingJobs) == 1) { EmptyEvent.Reset(); } ThreadPool.QueueUserWorkItem(Execute, ActionToExecute); } /// /// Internal method to execute an action /// /// The action to execute void Execute(object ActionToExecute) { ((Action)ActionToExecute)(); if(Interlocked.Decrement(ref NumOutstandingJobs) == 0) { EmptyEvent.Set(); } } /// /// Waits for all queued tasks to finish /// public void Wait() { EmptyEvent.WaitOne(); } /// /// Waits for all queued tasks to finish, or the timeout to elapse /// /// Maximum time to wait /// True if the queue completed, false if the timeout elapsed public bool Wait(int MillisecondsTimeout) { return EmptyEvent.WaitOne(MillisecondsTimeout); } } }