2010-07-07 17 views
8

Soy nuevo en el subprocesamiento en C#. ¿Hay alguna forma de establecer un tiempo de espera para un hilo sin bloquear el hilo de llamada (en C# 3.5)?Tiempo de espera del subproceso en C#

Si no es así, ¿es lógico ejecutar una función usando un hilo y dentro de esa función crear un hilo y unirlo para superar este problema principal de bloqueo de hilo? Para ilustrar:

En lugar de:

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

usando algo como:

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

Similar http://stackoverflow.com/questions/299198/implement-c-sharp-generic-timeout – Kiquenet

Respuesta

4

he comprobado y la forma más sencilla y más completa de hacerlo era la solución que he mencionado en la descripción de la pregunta. Un hilo de nivel medio puede esperar fácilmente el segundo hilo sin ninguna interrupción sobre el hilo principal; y puede matar el segundo hilo si no responde dentro del tiempo requerido. Eso es exactamente lo que necesitaba. Lo usé y funcionó sin problemas.

+0

Solo estoy agregando esta respuesta en caso de que alguien se encuentre con el mismo problema y quiere ver dónde llegué al final. Gracias a todos por su ayuda. – DeveloperInToronto

0

Lo más fácil hacer es llamar al Thread.Join en puntos seguros de su hilo principal y pase la cantidad de tiempo que desea esperar para que ocurra la unión.

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

Cómo evitar el hilo.El envío siempre es una buena idea. Evitarlo en un hilo que no creaste es aún mejor. Cómo detener un hilo en .NET (y por qué Thread.Abort is Evil) http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation Dangers of Thread.Abort por Eric Lippert http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx – Kiquenet

+0

@Kiquenet que ya mencionó como "Esta es una operación insegura así que utilízalo como último recurso ". para abortar el hilo. En cambio, la señalización se puede usar para devolver el hilo de bloqueo de forma segura. –

1

También puede ser que desee echar un vistazo a ThreadPool.QueueUserWorkItem() (http://msdn.microsoft.com/en-us/library/kbf0f1ct.aspx), que hace un montón de cosas para usted.

Como comentó Brian, abortar un hilo por lo general no es una tarea inteligente, porque podría estar en medio de hacer algunas cosas importantes en ese momento.

0

"Unir miembro -> Bloquea el hilo de llamada hasta que finaliza un subproceso, mientras continúa ejecutando COM estándar y el bombeo SendMessage". Sitio web de MSDN.

thrd1.Join() indican al hilo de llamada que espere hasta la finalización del thrd1.

Mi solución favorita es hacer una pequeña clase que sea capaz de controlar la ejecución del hilo.

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

Mire el método WaitHandle.WaitOne() con el esquema 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(); 
} 

No estoy seguro de qué pasaría con el hilo sin terminar, sin embargo.

2

Puede iniciar System.Threading.Timer para cada subproceso y pasarlo ManagedThreadId del subproceso. Mantenga diccionarios para los hilos activos y sus temporizadores, codificados por ManagedThreadId. Si un temporizador expira, use la ID del hilo pasado para abortar el hilo y matar su temporizador. Si el hilo termina normalmente, invoque una devolución de llamada que mate el temporizador. He aquí un ejemplo simple consola:

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

Evitar hilo. El envío siempre es una buena idea. Evitarlo en un hilo que no creaste es aún mejor. Cómo detener un hilo en .NET (y por qué Thread.Abort is Evil) http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation Dangers of Thread.Abort por Eric Lippert http://blogs.msdn.com/b/ericlippert/archive/2010/02/22/should-i-specify-a-timeout.aspx – Kiquenet

Cuestiones relacionadas