You can start a System.Threading.Timer for each thread and pass it the thread's ManagedThreadId. Keep dictionaries for the active threads and their timers, keyed by the ManagedThreadId. If a timer expires, use the passed thread ID to abort the thread and kill its timer. If the thread finishes normally, invoke a callback that kills the timer. Here's a simple console example:
using System;
using System.Collections.Generic;
using System.Threading;
namespace ConsoleApplication2
{
public delegate void KillTimerDelegate(int arg);
class Program
{
static Dictionary<int, Thread> activeThreads = new Dictionary<int, Thread>();
static Dictionary<int, Timer> activeTimers = new Dictionary<int, Timer>();
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Worker worker = new Worker();
worker.DoneCallback = new KillTimerDelegate(KillTimer);
Thread thread = new Thread(worker.DoWork);
activeThreads.Add(thread.ManagedThreadId, thread);
thread.IsBackground = true;
thread.Start();
Timer timer = new Timer(TimerCallback, thread.ManagedThreadId, 500, 500);
activeTimers.Add(thread.ManagedThreadId, timer);
}
Console.ReadKey();
}
static void TimerCallback(object threadIdArg)
{
int threadId = (int)threadIdArg;
if (activeThreads.ContainsKey(threadId))
{
Console.WriteLine("Thread id " + threadId.ToString() + " aborted");
activeThreads[threadId].Abort();
KillTimer(threadId);
}
}
static void KillTimer(int threadIdArg)
{
activeThreads.Remove(threadIdArg);
activeTimers[threadIdArg].Dispose();
activeTimers.Remove(threadIdArg);
}
}
public class Worker
{
public KillTimerDelegate DoneCallback { get; set; }
Random rnd = new Random();
public void DoWork()
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + " started");
Thread.Sleep(rnd.Next(0, 1000));
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + " finished normally");
DoneCallback(Thread.CurrentThread.ManagedThreadId);
}
}
}