Search code examples
c#multithreadingc#-4.0thread-synchronization

Blocking a thread for longer than Int32.MaxValue


I am working on a project that needs to block a running thread for a time span that can vary between one second and several months.

The approach I came up with was to use the EventWaitHandle.WaitOne method (or any of its siblings) with a timeout specified. The problem is that all these methods take an Int32 as a parameter which caps the maximum block time to roughly 25 days.

Does anybody know a solution to this? How can I block a thread for longer that Int32.MaxValue milliseconds?

thanks

UPDATE

Just for the records, here's the code snippet I finally came up with:

while(_doRun)
{
  // Determine the next trigger time
  var nextOccurence = DetermineNextOccurence();
  var sleepSpan = nextOccurence - DateTime.Now;

  // if the next occurence is more than Int32.MaxValue millisecs away,
  // loop to work around the limitations of EventWaitHandle.WaitOne()
  if (sleepSpan.TotalMilliseconds > Int32.MaxValue) 
  {
    var idleTime = GetReasonableIdleWaitTimeSpan();
    var iterationCount = Math.Truncate(sleepSpan.TotalMilliseconds / idleTime.TotalMilliseconds);
    for (var i = 0; i < iterationCount; i++)
    {
      // Wait for the idle timespan (or until a Set() is called).
      if(_ewh.WaitOne(idleTime)) { break; }
    }
  }
  else
  {
    // if the next occurence is in the past, trigger right away
    if (sleepSpan.TotalMilliseconds < 0) { sleepSpan = TimeSpan.FromMilliseconds(25); }

    // Wait for the sleep span (or until a Set() is called).
    if (!_ewh.WaitOne(sleepSpan))
    {
      // raise the trigger event
      RaiseTriggerEvent();
    }
  }
}

That snippet is the code executed by a dedicated thread. Note that EventWaitHandle.Set() is only called when the Application quits or whishes to cancel the scheduler.

Thanks to those willing to help.


Solution

  • Try handle.WaitOne(System.Threading.Timeout.Infinite).

    If you don't want it to run infinitely, trigger the wait handle externally from a different thread.

    UPDATE:

    If you don't want to use another thread, use a loop:

    bool isTriggered = false;
    while (!isTriggered) {
        isTriggered = handle.WaitOne(timeout);
        //Check if time is expired and if yes, break
    }
    

    You have to split your timeout timespan into multiple chunks that will fit into an Int32. The isTriggered variable will show you if the handle was triggered or if it timed out.