135 lines
5.2 KiB
C#
135 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
|
|
namespace DTS.Common.Utilities
|
|
{
|
|
/// <summary>
|
|
/// this is a class to simplify waiting for a resource
|
|
/// it can wait for a specified period and also check another signal or condition
|
|
/// </summary>
|
|
public class WaitWithCondition
|
|
{
|
|
/// <summary>
|
|
/// the max time to wait in any spin cycle
|
|
/// </summary>
|
|
/// <remarks>this should probably be private and never modified as it will affect all
|
|
/// waitwithcondition instances.
|
|
/// if a wait condition is created with a 1000 millisecond wait period, and the EachWaitMilliSec
|
|
/// was 20, we would wait for 50 cycles of 20ms before our final timeout
|
|
/// </remarks>
|
|
public static int EachWaitMilliSec = 20; // we wait 0.02 second each time
|
|
|
|
/// <summary>
|
|
/// optional function to check while waiting for handle to return.
|
|
/// </summary>
|
|
/// <returns>bool if condition has been met, false otherwise</returns>
|
|
public delegate bool Condition();
|
|
|
|
/// <summary>
|
|
/// this exception is used to indicate a condition was met to the calling code
|
|
/// </summary>
|
|
public class ConditionMetException : ApplicationException
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// waits either for work to be finished (signaled by workevent),
|
|
/// timeout, or the work to be canceled
|
|
/// returns false if timed out, returns true if work completed
|
|
/// throws an exception if canceled?
|
|
/// (note this should be the same behavior as Wait(handle, int, condition)
|
|
/// 17600 Communication class improvements from 3.2
|
|
/// </summary>
|
|
public static bool Wait(WaitHandle workEvent, int toMS, WaitHandle cancelEvent)
|
|
{
|
|
var res = WaitHandle.WaitAny(new[] { workEvent, cancelEvent }, toMS);
|
|
//nothing signalled
|
|
if (WaitHandle.WaitTimeout == res) { return false; }
|
|
|
|
if (0 == res) { return true; }
|
|
throw new ConditionMetException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// wait for a resource to be available
|
|
/// </summary>
|
|
/// <param name="handle"><see cref="System.Threading.WaitHandle" /> object to wait on</param>
|
|
/// <param name="toMilliSec">max amount of time in milliseconds to wait
|
|
/// use <see cref="System.Threading.Timeout.Infinite" /> to wait for the max amount of time
|
|
/// allowed.
|
|
/// </param>
|
|
/// <param name="condition">an additional condition to check. Can be null.
|
|
/// if condition is met before resource is available a <see cref="WaitWithCondition.ConditionMetException" />
|
|
/// is thrown.
|
|
/// </param>
|
|
/// <returns>true indicates the <see cref="System.Threading.WaitHandle" /> object has returned within
|
|
/// the requested time period, false otherwise
|
|
/// </returns>
|
|
public static bool Wait(WaitHandle handle, int toMilliSec, Condition condition)
|
|
{
|
|
var NumberOfWaits = 1;
|
|
|
|
// check for infinity
|
|
if (toMilliSec < 0)
|
|
{
|
|
if (toMilliSec != System.Threading.Timeout.Infinite)
|
|
{
|
|
throw new ArgumentException("WaitWithCondition.Wait: invalid timeout value");
|
|
}
|
|
// they want to wait forever, a billion seconds is pretty long
|
|
NumberOfWaits = 1000000000;
|
|
}
|
|
else if (toMilliSec == 0)
|
|
{
|
|
// 0 means no wait just check
|
|
EachWaitMilliSec = 0;
|
|
}
|
|
else
|
|
{
|
|
// they want to wait X milli seconds,
|
|
// first make sure that isn't shorter than our eachWaitMilliSec
|
|
if (toMilliSec < EachWaitMilliSec)
|
|
{
|
|
// yes it is, adjust our wait
|
|
EachWaitMilliSec = toMilliSec;
|
|
}
|
|
else
|
|
{
|
|
// no, how many times do we have to try?
|
|
NumberOfWaits = toMilliSec / EachWaitMilliSec;
|
|
}
|
|
}
|
|
for (var idx = 0; idx < NumberOfWaits; idx++)
|
|
{
|
|
if (handle.WaitOne(EachWaitMilliSec, false))
|
|
{
|
|
// no timeout, we have data but check cancel first
|
|
if ((null != condition))
|
|
{
|
|
if (condition())
|
|
{
|
|
throw new ConditionMetException();
|
|
}
|
|
}
|
|
// no, give it to them
|
|
return true;
|
|
}
|
|
|
|
// timeout. check for cancel before looping
|
|
if ((null != condition))
|
|
{
|
|
if (condition())
|
|
{
|
|
throw new ConditionMetException();
|
|
}
|
|
}
|
|
}
|
|
// we didn't get anything, return timeout
|
|
return false;
|
|
}
|
|
}
|
|
}
|