using System;
using System.Threading;
class Program
{ static void Main(string[] args)
{ AsyncJobClass.Ready = false;
AsyncJobClass.DoAsyncJob(false);
//Test 1, Timoeout = 8s
AsyncToSyncHelper.CheckStatusWithTimeout(
() => { return AsyncJobClass.Ready; }, 100, 8000, "Test 1");
Console.WriteLine("Test 1, shorter than timeout, OK!");
try
{ AsyncJobClass.Ready = false;
AsyncJobClass.DoAsyncJob(false);
//Test 2, Timeout = 3s
AsyncToSyncHelper.CheckStatusWithTimeout(
() => { return AsyncJobClass.Ready; }, 100, 3000, "Test 2");
}
catch (Exception e)
{ Console.WriteLine("Error=" + e.Message); Console.WriteLine("Test 2, longer than timeout, OK!"); }
try
{ AsyncJobClass.Ready = false;
AsyncJobClass.DoAsyncJob(true);
//when error, use RaiseCheckStatusException() to stop
AsyncJobClass.OnError = (e) =>
{ AsyncToSyncHelper.RaiseCheckStatusException(e);
};
//Test 3, throw the exception in purpose
AsyncToSyncHelper.CheckStatusWithTimeout(
() => { return AsyncJobClass.Ready; }, 100, 8000, "Test 3");
}
catch (Exception e)
{ Console.WriteLine("Error=" + e.Message); Console.WriteLine("Test 3, stopped when exception, OK!"); }
Console.Read();
}
}
/// <summary>
/// An helper class to sync with async job
/// </summary>
public class AsyncToSyncHelper
{ public static Exception CheckStatusException = null;
/// <summary>
/// Check the status function until it return true or timeout
/// </summary>
/// <param name="check">return true when ready</param>
/// <param name="interval">interval of checking in milliseconds</param>
/// <param name="period">timeout period in milliseconds</param>
/// <param name="jobDesc">job description for timeout exception message</param>
public static void CheckStatusWithTimeout(Func<bool> check, int interval,
long period, string jobDesc)
{ DateTime dtTimeout = DateTime.Now.AddMilliseconds(period);
CheckStatusException = null;
while (DateTime.Now.CompareTo(dtTimeout) < 0 && !check()
&& CheckStatusException == null)
Thread.Sleep(interval);
if (CheckStatusException != null)
throw new ApplicationException("CheckStatusWithTimeout Exception: " + CheckStatusException.Message);
if (DateTime.Now.CompareTo(dtTimeout) >= 0)
throw new ApplicationException(
string.Format(
"CheckStatusWithTimeout Exception: Timeout after {0:N0}ms @ {1}", period, jobDesc));
}
private static object _lock = new object();
/// <summary>
/// Raise an exception to stop CheckStatusWithTimeout
/// </summary>
/// <param name="e"></param>
public static void RaiseCheckStatusException(Exception e)
{ lock (_lock)
{ CheckStatusException = e;
}
}
}
class AsyncJobClass
{ public static bool Ready = false;
//Simulating async work
//delay 5 sec, than set Ready = true, or throw an exception in purpose
public static void DoAsyncJob(bool raiseException)
{ ThreadPool.QueueUserWorkItem((o) => { if (raiseException)
OnError(new ApplicationException("Exception in Purpose!")); else
{ Thread.Sleep(5000);
Ready = true;
}
});
}
//The event triggered when exception raised
public static Action<Exception> OnError;
}