2009-12-22 6 views
3

J'ai un Windows Form et une classe avec deux méthodes simples qui s'exécutent de manière récursive de manière non déterministe (ce qui signifie que la récursivité est inconnue, les deux peuvent appeler l'autre) ... Maintenant, il y a des points durant cette récursion au cours de laquelle je veux mettre en pause l'exécution et attendre qu'un utilisateur clique sur le bouton "Next Step". Ce n'est que lorsque le bouton est pressé que les fonctions récursives continuent. La classe s'exécute sur un thread séparé afin de ne pas bloquer l'interface utilisateur.Comment mettre en pause le fil d'arrière-plan, puis continuer sur le bouton cliquer?

Pendant cette pause, le formulaire récupérerait simplement la valeur de la classe et l'afficherait dans une zone de liste. Ensuite, après avoir appuyé sur le bouton, la récursivité continue jusqu'à la pause suivante(). J'ai besoin de cela pour que l'utilisateur puisse voir ce qui se passe dans la récursion étape par étape. Aussi je dois pouvoir mettre Pause() n'importe où dans la méthode récursive (même plusieurs fois) sans causer d'effets secondaires ...

La seule façon qui me vient à l'esprit est d'appeler la méthode Pause() dans qu'une boucle vérifie un drapeau verrouillé puis dort pendant un certain temps (le bouton mettrait alors le drapeau), mais j'ai eu de mauvaises expériences avec Thread.Sleep() dans Windows Forms (en verrouillant l'interface utilisateur) donc je regarde une autre option .

Existe-t-il un moyen propre de faire cela?

Répondre

6

Utilisez un ManualResetEvent initialisé à true, afin qu'il commence à être défini. À un endroit bien connu dans une méthode ou l'autre (ou les deux), attendez l'événement. La plupart du temps, l'événement sera défini pour que le thread d'arrière-plan continue immédiatement. Lorsque l'utilisateur clique sur Pause, toutefois, réinitialise l'événement, provoquant le blocage du thread d'arrière-plan la prochaine fois qu'il atteint l'événement. Lorsque l'utilisateur clique sur "Reprendre", définit l'événement, permettant au thread d'arrière-plan de continuer à nouveau.

Il n'y a aucune raison pour que le thread UI ne bloque jamais dans ce scénario.

+0

Cela a fonctionné avec une petite modification car l'utilisateur ne fait pas de pause, la fonction elle-même s'arrête. L'utilisateur effectue uniquement l'étape. Mais j'ai mis Reset() et WaitOne() dans ma Pause(), puis sur le bouton cliquez simplement sur Set(). Cela fonctionne comme prévu. C'est marrant comme je n'ai jamais remarqué cette classe. –

+0

C'est ainsi que fonctionne AutoResetEvent. Il se réinitialise automatiquement lorsqu'un thread l'attend avec succès. –

+0

Oui, AutoResetEvent fonctionne également pour mon scénario et crée un code plus court (d'une ligne). Donc maintenant je peux seulement appeler WaitOne() dans ma Pause() avec le reste du code laissé inchangé. –

2

Utilisez un objet AutoResetEvent. Appelez la méthode .WaitOne à partir de votre thread pour le mettre en pause, et appelez la méthode .Set à partir de votre bouton pour le réactiver.

+0

Un 'AutoResetEvent' ne fonctionnera pas comme prévu dans ce scénario. –

+0

Ne fonctionnera pas dans ce scénario parce que ...? –

+0

Ca fonctionne, donc il n'y en a pas parce que :) –

1

Ceci est un bon endroit pour utiliser un Mutex d'une manière non standard. Faites en sorte que votre thread de fond prenne et libère le Mutex quand il est dans une position où il est bon d'attendre.

Demandez à votre thread GUI prendre le Mutex quand il veut bloquer le thread d'arrière-plan, et le relâcher quand c'est bon pour qu'il s'exécute. De cette façon, le thread d'arrière-plan attendra quand il le devrait, et flashera simplement dans et hors du Mutex quand il est autorisé à fonctionner. Pensez au «droit d'exécution» en tant que ressource protégée par la section critique.

comme celui-ci

// this object has to be visible to both threads 
System.Threading.Mutex mtx = new Mutex(); 

// worker thread does this wherever it's ok for it to pause 
mtx.WaitOne(); 
mtx.ReleaseMutex(); 

// main thread does this to pause the worker 
Mtx.WaitOne(); 

// main thread does this this to unpause it. 
mtx.ReleaseMutex(); 
Questions connexes