// 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);
}
}
}