2010-02-12 4 views
2

J'ai fait des recherches et regardé autour de moi et il me semble que la façon de procéder est d'utiliser un AutoResetEvent. J'ai rapidement mis cela ensemble et cela semble fonctionner et semble être sans danger pour les threads. Puis-je avoir des commentaires?.Net Thread.Suspend est obsolète. Je cherchais une alternative

class Program 
{ 
    private Thread workerThread; 
    private AutoResetEvent aResetEvent; 
    private bool _continueProcessing; 
    private bool active; 
    private Object locker = new Object(); 

    public Program() 
    { 
     workerThread = new Thread(DoSomeProcessing); 
     workerThread.IsBackground = true; 
     aResetEvent = new AutoResetEvent(false); 
    } 

    public bool ContinueProcessing 
    { 
     get 
     { 
      lock (locker) 
      { 
       return _continueProcessing; 
      } 
     } 
     set 
     { 
      if (value) 
      { 
       aResetEvent.Set(); 
      } 
      else 
      { 

       aResetEvent.Reset(); 
      } 
      lock (locker) 
      { 
       _continueProcessing = value; 
      } 
     } 
    } 

    public void DoSomeProcessing() 
    { 
     int i = 0; 
     try 
     { 
      while (active) 
      { 
       aResetEvent.WaitOne(); 
       // do some work and sleep 
       lock (locker) 
       { 
        if (ContinueProcessing) 
        { 
         aResetEvent.Set(); 
        } 
       } 
      } 
     } 
     catch(ThreadInterruptedException tie) 
     { 
      Console.WriteLine("Shutting down."); 
     } 
     // any shutdown processing    
    } 

    public void StopProcessing() 
    { 
     workerThread.Interrupt(); 
     workerThread.Join(); 
    } 

    public void PauseProcessing() 
    { 
     ContinueProcessing = false; 
    } 

    public void Continue() 
    { 
     ContinueProcessing = true; 
    } 

    public void StartProcessing() 
    { 
     ContinueProcessing = true; 
     active = true; 
    } 
} 

EDIT: Salut à nouveau. J'ai utilisé les commentaires et je suis beaucoup plus satisfait de ma mise en œuvre. Juste une petite chose que j'aimerais ajouter, quand je fais une pause je voudrais attendre pour m'assurer que le fil a fait une pause et qu'il ne travaille plus. Est-ce possible? Peut-être que je devrais juste remplacer la pause et reprendre avec seulement le début et l'arrêt, puis sur l'arrêt faire un thred.join(). Commentaires?

+1

Je me demande si vous auriez des problèmes de commande dans votre setter ContinuezProcessing? – ziya

+0

vous définissez _continueProcessing deux fois - verrouillé et déverrouillé – tanascius

+0

Peut-être que vous devriez mettre le verrou autour de tous (dans ContinuousProcessing setter) ou envisager un moyen de ne pas utiliser le drapeau? http://dotnet.org.za/markn/archive/2008/10/21/net-memory-model-bytecode-reordering.aspx – ziya

Répondre

1

Une fois que exit est appelé, ManualResetEvent sera éliminé et des exceptions pourront être levées sur les méthodes d'instance lorsqu'il est appelé. -> cela peut ne pas être souhaitable dans certains cas

class Program { 
     static void Main(string[] args) { 

      //NOTE: if worker goes out of scope it will be collected -> ex: promote to field in real use 
      Worker worker = new Worker(); 
      System.Threading.Thread workerThread = new System.Threading.Thread(new System.Threading.ThreadStart(worker.DoWork)); 
      workerThread.IsBackground = true; 
      workerThread.Start(); 

      // test 
      worker.Resume(); 
      System.Threading.Thread.Sleep(2000); 

      worker.Pause(); 
      System.Threading.Thread.Sleep(2000); 

      worker.Resume(); 
      System.Threading.Thread.Sleep(2000); 

      worker.Exit(); 
      System.Threading.Thread.Sleep(5000);   
     } 
    } 

    public class Worker { 

     private readonly System.Threading.ManualResetEvent _Gate; 
     private bool _IsActive; 

     public Worker() { 

      _Gate = new System.Threading.ManualResetEvent(false); 
      _IsActive = true; 
     } 

     public void DoWork() { 

      while (IsActive) { 
       _Gate.WaitOne(); 
       // do work 

       // can yield the thread 
       System.Threading.Thread.Sleep(1); 
      } 

      // dispose 
      _Gate.Close(); 
     } 

     private bool IsActive { 
      get { 
       lock (_Gate) { 
        return _IsActive; 
       } 
      } 
     } 

     public void Pause() { 
      _Gate.Reset(); 
     } 

     public void Resume() { 
      _Gate.Set(); 
     } 

     public void Exit() { 
      lock (_Gate) { 
       _IsActive = false; 
      } 
     } 
    } 
0

ressemble peut être enlevé trop complexe

et

public void StopProcessing() 
    { 
     workerThread.Interrupt(); 
     workerThread.Join(); 
    } 

si vous laissez juste la sortie du fil de la méthode

0

Si vous avez changé à l'aide d'un ManualResetEvent vous pouvez supprimer la variable _continueProcessing. Dans l'ensemble, appelez simplement Set ou Reset sur l'événement. Dans le getter, vous pouvez renvoyer aResetEvent.WaitOne (0). Vous pouvez ensuite supprimer le morceau de code à la fin de DoSomeProcessing qui définit l'événement si le traitement doit être contine. De plus, parce que ManualResetEvent est lui-même thread safe, vous pouvez supprimer complètement votre verrouillage.

En ce qui concerne la sortie de votre méthode DoSomeProcessing. Probablement la meilleure chose à faire est d'utiliser un drapeau que vous avez défini pour dire à la boucle de sortir, de tester le drapeau avec un verrou au début de la boucle (oui, vous devez maintenant mettre un peu de recul) et quand vous voulez pour annuler, vous définissez le drapeau, puis définissez l'événement.

Alternativement, vous pouvez utiliser un autre événement pour signaler que la boucle doit quitter et modifier votre attente pour utiliser WaitHandle.WaitAny().