c#中的线程超时

时间:2010-07-07 13:20:20

标签: c# multithreading

我是C#线程的新手。 有没有为线程设置超时而不阻塞调用线程(在C#3.5中)?

如果没有,使用线程执行函数是否合乎逻辑,并且在该函数内创建一个线程并加入它来克服这个主线程阻塞问题?举例说明:

而不是:

Public void main()
{
        ...
        Thread thrd1 = new Thread(new ThreadStart(targetObj.targetFunc));
        thrd1.Start();
        thrd1.Join();
        ...
}

使用类似的东西:

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

8 个答案:

答案 0 :(得分:4)

我检查过,最简单,最全面的方法就是我在问题描述中提到的解决方案。中级线程可以轻松地等待第二个线程而不会中断主线程;如果它在所需的时间内没有响应,它可以杀死第二个线程。这正是我所需要的。我使用它并且它没有问题。

答案 1 :(得分:2)

您可以为每个线程启动System.Threading.Timer并将其传递给线程的ManagedThreadId。保留活动线程及其计时器的字典,由ManagedThreadId键入。如果计时器到期,请使用传递的线程ID中止线程并终止其计时器。如果线程正常完成,则调用杀死计时器的回调。这是一个简单的控制台示例:

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

答案 2 :(得分:1)

您可能还想看一下为您做很多事情的ThreadPool.QueueUserWorkItem()http://msdn.microsoft.com/en-us/library/kbf0f1ct.aspx)。

正如布莱恩评论的那样,中止线程通常不是一件明智的事情,因为在那一刻它可能正在做一些重要的事情。

答案 3 :(得分:0)

答案 4 :(得分:0)

最简单的方法是在主线程的安全点调用Thread.Join并传入您希望等待联接发生的时间。

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.
  }
}

答案 5 :(得分:0)

“加入成员 - &gt;阻止调用线程,直到线程终止,同时继续执行标准COM和SendMessage抽取。” MSDN网站。

thrd1.Join()告诉调用线程等到thrd1完成。

我最喜欢的解决方案是创建一个小类,我可以控制线程的执行。

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

答案 6 :(得分:0)

使用middleObject方案查看WaitHandle.WaitOne()方法。

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

不确定未完成的线程会发生什么。

答案 7 :(得分:-1)

我创建了一个 C# 类来执行带有超时的线程,并且不会阻塞调用线程。

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

使用这个类:

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