开发者

Thread timeout in c#

开发者 https://www.devze.com 2023-01-06 12:12 出处:网络
I\'m new to threading in C#. Is there anyway of setting a timeout for a thread without blocking the calling thread (in C# 3.5)?

I'm new to threading in C#. Is there anyway of setting a timeout for a thread without blocking the calling thread (in C# 3.5)?

If not, is it logical to execute a function using a thread and within that function create a thread and join it to overcome this main thread blocking issue? To illustrate:

Instead of:

Public void main()
{
        ...
        Thread thrd1 = new Thread(new ThreadStart(targetObj.targetFunc));
        thrd1.Start();
        thrd1.Join();
        ...开发者_开发问答
}

Using something like:

Public void main()
{
        ...
        Thread thrd1 = new Thread(new ThreadStart(middleObj.waiter));
        thrd1.Start();
        ...
}

//And in the middleObj.waiter():
Public void waiter()
{
        Thread thrd2 = new Thread(new ThreadStart(targetObj.targetFunc));
        thrd2.Start();
        thrd2.Join();
}


I checked and the simplest and most comprehensive way of doing it was the solution I mentioned in the description of the question. A middle level thread can easily wait for the second thread without any interruption over the main thread; and it can kill the second thread if it does not respond within the required time. That's exactly what I needed. I used it and it worked without a problem.


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);
        }
    }
}


You might also want to take a look at ThreadPool.QueueUserWorkItem() ( http://msdn.microsoft.com/en-us/library/kbf0f1ct.aspx ) which does a lot of stuff for you.

As Brian commented, aborting a thread is usually not a smart thing to do, because it could be in the middle of doing some important stuff at that moment.


Look at WaitHandle.WaitOne() method with the middleObject scheme.

Public void main()
{
    ...
    middleObj.WaitHandle.Reset();
    Thread thrd1 = new Thread(new ThreadStart(middleObj.waiter));
    thrd1.Start();
    middleObj.WaitHandle.WaitOne(timeout);
    ...
}


//And in the middleObj.waiter():
Public void waiter()
{
    Thread thrd2 = new Thread(new ThreadStart(targetObj.targetFunc));
    thrd2.Start();
    thrd2.Join();
    this.WaitHandle.Set();
}

Not sure what would happen to the unfinished thread, though.


See this: http://www.techtalkz.com/c-c-sharp/111717-thread-timeout.html

Check out the TimeSpan method http://msdn.microsoft.com/en-us/library/23f7b1ct.aspx


The easiest thing to do is to call Thread.Join at safe points from your main thread and pass in the amount of time you want to wait for the join to occur.

public static void Main()
{
  TimeSpan timeout = TimeSpan.FromSeconds(30);
  Thread thread = new Thread(() => { ThreadMethod(); });
  thread.Start();
  DateTime timeStarted = DateTime.UtcNow;
  DoSomeWorkOnThisThread();
  // We are at a safe point now so check the thread status.
  TimeSpan span = DateTime.UtcNow - timeStarted; // How long has the thread been running.
  TimeSpan wait = timeout - span; // How much more time should we wait.
  if (!thread.Join(wait))
  {
    thread.Abort(); // This is an unsafe operation so use as a last resort.
  }
}


"Join member--> Blocks the calling thread until a thread terminates, while continuing to perform standard COM and SendMessage pumping." MSDN website.

thrd1.Join() tell the calling thread to wait until the completion of the thrd1.

My favorite solution is to make a small class which i'm able to control the execution of thread.

public class MyClass
    {
        private bool _stop;
        private Thread _myThread;

        public void Stop()
        {
            _stop = true;
            //Will block the calling thread until the thread die
            _myThread.Join();
        }

        public void Run()
        {
            _stop = false;
            _myThread = new Thread(Work);
        }

        public void Work()
        {
            do
            {

            } while (!_stop);
        }
   }


I have created a C# class to execute Threads with timeout, and without blocking the calling Thread.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Timers;

namespace some_name_space
{
    class TimedThread
    {
        private Thread thread;
        private static List<TimedThread> timedThreads = new List<TimedThread>();
        private Int32 timeout = 5000;
        private System.Timers.Timer timer;
        public TimedThread(ThreadStart start) { thread = new Thread(start); }        

        public int Timeout { get => timeout; set => timeout = value; }
        public System.Timers.Timer Timer { get => timer; }
        public Thread _Thread { get => thread; }

        public void run()
        {
            timer = new System.Timers.Timer(timeout);
            timer.Elapsed += OnTimedEvent;
            timer.AutoReset = false;
            timer.Enabled = true;
            _Thread.Start();
        }
        private static void OnTimedEvent(Object source, ElapsedEventArgs e)
        {
            TimedThread tt = timedThreads.Find(t => t.timer.Equals(source));
            if (tt != null)
                tt.thread.Abort("Timeout exception");
        }
    }
}

Using this class:

TimedThread tt = new TimedThread(SomeWorkToDo);
tt.Timeout = 5000;
tt.run();
0

精彩评论

暂无评论...
验证码 换一张
取 消