using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace DTS.Common.Utilities { /// /// this is a class to simplify waiting for a resource /// it can wait for a specified period and also check another signal or condition /// public class WaitWithCondition { /// /// the max time to wait in any spin cycle /// /// 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 /// public static int EachWaitMilliSec = 20; // we wait 0.02 second each time /// /// optional function to check while waiting for handle to return. /// /// bool if condition has been met, false otherwise public delegate bool Condition(); /// /// this exception is used to indicate a condition was met to the calling code /// public class ConditionMetException : ApplicationException { } /// /// 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 /// 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(); } /// /// wait for a resource to be available /// /// object to wait on /// max amount of time in milliseconds to wait /// use to wait for the max amount of time /// allowed. /// /// an additional condition to check. Can be null. /// if condition is met before resource is available a /// is thrown. /// /// true indicates the object has returned within /// the requested time period, false otherwise /// 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; } } }