Я плохо знаком с поточной обработкой в 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();
}
Возможно, вы также захотите взглянуть на ThreadPool.QueueUserWorkItem()
( http://msdn.microsoft.com/en-us/library/kbf0f1ct.aspx ), который делает многое за вас.
Как заметил Брайан, прерывание потока обычно не является разумным действием, поскольку в этот момент он может быть занят какими-то важными делами.
См. Это: http://www.techtalkz.com/cc-sharp/111717-thread-timeout.html
Ознакомьтесь с методом TimeSpan http://msdn.microsoft.com/en-us/library/23f7b1ct .aspx
Проще всего вызвать 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.
}
}
«Присоединиться к члену -> Блокирует вызывающий поток, пока поток не завершится, продолжая выполнять стандартную перекачку 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);
}
}
Посмотрите на метод WaitHandle.WaitOne() со схемой middleObject.
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();
}
Хотя не уверен, что произойдет с незавершенным потоком.
Вы можете запустить System.Threading.Timer для каждого потока и передать ему ManagedThreadId потока. Храните словари для активных потоков и их таймеров с ключом ManagedThreadId. Если таймер истекает, используйте переданный идентификатор потока, чтобы прервать поток и убить его таймер. Если поток завершится нормально, вызовите обратный вызов, который убьет таймер. Вот простой консольный пример:
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);
}
}
}