C# Wait for all threads completed with timeout
We only want to do something after all threads finish their work. The advantage is that all the threads can work simultaneously while each of them has no dependency to the other. Typically, I found it improves efficiency when making call to the remove webservice.
For example, there is a web service operation called getProductById(int id), the problem is the getProductById API only allows you to pass in single Id at a time. When at client side, you need to fetch a list of products at the same time, in this case, we can make each thread to retrieve one product from the service and merge all the result after all threads complete.
Here is the extention method “WaitAll” for generic Thread IEnumerable object,
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
namespace Auva.Core.Utilities
{
/// <summary>
/// Contains thread utilities.
/// </summary>
public static class ThreadUtil
{
/// <summary>
/// Delegate that will be called after thread timeout.
/// </summary>
public delegate void ThreadTimeoutHandler(Thread thread);
/// <summary>
/// Waits all threads with timeout defined.
/// </summary>
/// <param name="threads">The threads.</param>
/// <param name="timeoutMilliSeconds">The timeout milli seconds.</param>
/// <param name="threadTimeoutCallback">The thread timeout callback.
/// e.g. perform Abort on thread in the handler</param>
/// <returns>Threads which were timeout.</returns>
public static IEnumerable<Thread> WaitAll(this IEnumerable<Thread> threads,
double timeoutMilliSeconds,
ThreadTimeoutHandler threadTimeoutCallback)
{
if (threads==null)
{
throw new ArgumentNullException(“threads”, “threads must be defined.”);
}
// caculate completion time
DateTime completionTime = DateTime.UtcNow
.AddMilliseconds(timeoutMilliSeconds);
// prepare a list for storing timeout threads
List<Thread> timeoutThreads = new List<Thread>();
// join each thread with a timeToLive timeout
foreach (Thread thread in threads)
{
// caculate completion time
TimeSpan timespan = completionTime – DateTime.UtcNow;
// time left before timeout
double timeToLive = timespan.TotalMilliseconds;
// join the thread with time left
if (!thread.Join(timeToLive > 0 ? Convert.ToInt32(timeToLive) : 0))
{
timeoutThreads.Add(thread);
Debug.WriteLine(string.Format(“Thread {0} timeout.”, thread.Name));
// callback, most likely, the callback will abort the thread
if (threadTimeoutCallback != null)
{
try
{
threadTimeoutCallback(thread);
}
catch (Exception x)
{
//silently handle the exception from callback
Debug.WriteLine(x.Message);
}
}
}
}
return timeoutThreads;
}
}
}
You might have notice, WaitAll also allows you to define the timeout, the method will invoke threadTimeoutCallback if a thread exceeded the timeoutMilliSeconds defined. This will basically give caller a chance to abort long running threads so that WaitAll will have a time to finish rather than an endless process.
Here is some code for testing it.
public void WaitAllTimeout()
{
// initialize all threads
List<Thread> list = new List<Thread>();
for (int i = 0; i < 5; i++)
{
Thread thread = new Thread(Worker);
thread.Name = “test” + i;
list.Add(thread);
thread.Start();
}
// start up all the threads by invoking the extension methods
list.WaitAll(5000, delegate(Thread thread)
{
// this will be called when the checking thread is timeout
Console.WriteLine(“TimeoutCallback thread: {0}”, thread.Name);
thread.Abort();
});
}
// the thread worker method
public void Worker()
{
// do some work with random duration
}
Occasionally, I found the thread is not being timed out for the given timeout value, normally a few milliseconds after, this is due to .net internal implementation of thread.Join(int timeToLive) that not being timed out strictly by the given value.
Please log a comment if you found bugs or some ideas of improving it. Thanks for Sharing.
Comment from misterG
Time August 8, 2009 at 4:38 am
please add the following line:
int timeout = 10000;
before this line:
list.WaitAll(timeout, delegate(Thread thread)