Question

I have an application which should finish within 30 minutes. The components of the application are run using threadpool.

So

//queue first all the components
//when the Collect method for each of the components finishes it will set the event
ManualResetEvent serverEvent = new ManualResetEvent(false);
sectionsCompleted.Add(serverEvent);
ThreadPool.QueueUserWorkItem(serverInfo.Collect,"ServerInfo ");

ManualResetEvent cpuEvent= new ManualResetEvent(false);
sectionsCompleted.Add(cpuEvent);
ThreadPool.QueueUserWorkItem(cpuInfo.Collect,"CPUInfo ");

//then wait for all the components to finish
WaitHandle.WaitAll(sectionsCompleted.ToArray());

So the logic is to call all the components in ThreadPool and use ManualResetEvent class to signal the main thread that the component has finished.

Now i want to use the ElapsedEvent Handler to make sure that the code finishes gracefully in some time frame(say 30 minutes). So after 30 minutes if there are still some threads running i want to abort them.

So my question will ElapsedEventHandler delegate be called at all? or will the main thread wait for WaitHandle.WaitAll(sectionsCompleted.ToArray()) ?

Is there any other way i can achieve this functionality of stopping all threads in a thread pool after some time interval.

Was it helpful?

Solution

If you setup the timer, the event handler for the timer, and start the timer before the above code (or at least before the WaitAll) then

  • your timer's Elapsed event will fire,
  • your Main thread will wait at the WaitAll

but you could just as easily do something like:

if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
  // did not finish in the 30 minute timespan, so kill the threads
}

If you do the above you won't have to worry about synchronising your event handler for the timer (which may try and kill a thread just as it completes) and the Main method which is waiting on the WaitHandles (and may therefore complete while the event handler thinks the thread is being killed).

If you are able (.NET version depending) then Tasks would be very well suited to this as you could use a CancellationToken to allow you to kill each task gracefully if it has not completed. See MSDN: Task Cancellation for something like the below. If you can't use Task you can just wire this same solution up yourself. One possible technique is to use more WaitHandles (also see below).

This approach will also let you move the Wait+Cancel code into a separate thread. You can therefore release your UI or main code thread immediately the worker threads are created. This has the added advantage that you can also signal from the control thread to the single instance of the Wait+Cancel code to trigger a premature cancellation.

// use the same CancellationTokenSource to create all tasks
var tokenSource2 = new CancellationTokenSource();

// for each task, use the following structure
CancellationToken ct = tokenSource2.Token;

var task = Task.Factory.StartNew(() =>
{
  // Were we already canceled?
  ct.ThrowIfCancellationRequested();

  bool moreToDo = true;
  // make sure any loops and other methods check the ct.IsCancellationRequested regularly
  while (moreToDo)
  {
    if (ct.IsCancellationRequested)
    {
      // Clean up any resources, transactions etc. here, then...
      ct.ThrowIfCancellationRequested();
    }
  }
}, tokenSource2.Token); // Pass same token to StartNew.

// add each task to the tasks list    
tasks.Add(task);

// once all tasks created, wait on them and cancel if they overrun
//   by passing the token, another thread could even cancel the whole operation ahead of time
if (!Task.WaitAll(tasks.ToArray(), (int)TimeSpan.FromMinutes(30).TotalMilliseconds, 
  tokenSource2.Token)) 
{      
  // did not finish in the 30 minute timespan, so kill the threads
  tokenSource2.Cancel();
  try
  {
    //    Now wait for the tasks to cancel
    Task.WaitAll(tasks.ToArray());
  }
  catch (AggregateException ae)
  {
    // handle any unexpected task exceptions here
  }
}

Or in .NET 2.0 without Tasks:

//  in Main  thread ...
ManualResetEvent serverEventCancelled = new ManualResetEvent(false);
cancellationMres.Add(serverEventCancelled);

// Inside the thread, do this regularly - zero timeout returns instantly ...
if (serverEventCancelled.WaitOne(0))
{
    // do cancellation and ...
    //   now set the "completed" waithandle (or do something similar to let Main know we are done)
    serverEvent.Set();
    return;
}

// In Main thread ...
if (!WaitHandle.WaitAll(sectionsCompleted.ToArray(), TimeSpan.FromMinutes(30)))
{
    foreach (var cancellationMre in cancellationMres)
    {
        cancellationMre.Set();
    }
    WaitHandle.WaitAll(sectionsCompleted.ToArray());
}

OTHER TIPS

ElapsedEventHandler delegate be called at all?

yes

will the main thread wait for WaitHandle.WaitAll(sectionsCompleted.ToArray()) ?

yes

but you need to signal the eventhandler in your thread(like cpuInfo.Collect) , in .net 4.5, you also can use CancellationTokenSource(TimeSpan) to cancel the thread after period time.

btw: you should put WaitHandle.WaitAll(sectionsCompleted.ToArray()) in non-ui thread, or it will block your UI.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top