2009-11-25 3 views
1

J'ai cette situation: un formulaire avec un System.Timer dedans (avec AutoReset = False). La forme a son fil principal et le minuteur son propre fil aussi (rien de nouveau ici). Lorsque l'utilisateur appuie sur un bouton, je dois arrêter la minuterie, attendre que le thread du minuteur ait arrêté son exécution et faire quelque chose de plus. De l'autre côté, la minuterie met à jour un élément dans le formulaire afin BeginInvoke est utilisé. Le code ressemble à ceci:Comment gérer cette situation Multithread et ne pas verrouiller?

Code Button:

Private Sub ButtonStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonStop.Click 
     SyncLock (m_stopLock) 
      m_stopProcessTimer = True 
      Threading.Monitor.Wait(m_stopLock) 
     End SyncLock 
     ''#Do more things here after the timer has end its execution and is stopped 
    End Sub 

Code Timer:

Private Sub m_processTimer_Elapsed(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_processTimer.Elapsed 
    Dim auxDelegate As EventHandler 

    SyncLock (m_stopLock) 
     If Not m_stopProcessTimer Then 
      If Me.InvokeRequired Then 
       auxDelegate = New EventHandler(AddressOf m_processTimer_Elapsed) 
       Me.BeginInvoke(auxDelegate, New Object() {sender, e}) 
      Else 
       DoFormStuf() 
       m_processTimer.Start() 
      End If 
     Else 
      Threading.Monitor.Pulse(m_stopLock) 
     End If 
    End SyncLock 
End Sub 

Le point est que j'attends le fil conducteur de laisser le fil de la minuterie pour terminer son travail.

Le problème est que ce code se bloque lorsque l'utilisateur clique sur le bouton lorsque le BeginInvoke va être appelé. Comment une chose aussi simple que celle-ci peut-elle être faite? On dirait que je ne peux pas trouver une bonne solution à ce problème :(

Répondre

2

Ne pas utiliser de verrous du tout, assurez-vous de faire tout sur le fil de l'interface utilisateur, et vous pouvez garantir que rien ne sera corrompu. exécuter sur le thread d'interface utilisateur, de sorte que vous savez que si vous faites tout ce que ce soit dans un élément répartiteur ou un gestionnaire d'événements, seul une chose est en cours d'exécution à la fois.

+0

Désolé, j'ai mis à jour le gestionnaire de boutons pour montrer que je dois attendre que l'exécution de la minuterie se termine et qu'elle soit arrêtée (elle ne s'exécute plus) et après que quelque chose soit fait. –

+0

Ne pas "attendre", il suffit que l'interface utilisateur ne fasse rien, et que le chronométreur déclenche l'élément du répartiteur pour terminer le reste. Vous ne pouvez pas bloquer dans un thread d'interface utilisateur de toute façon, sinon l'interface utilisateur va se bloquer. –

+0

Ok, maintenant je vois ce que vous voulez dire. C'est une sorte de rappel appelé du code temporisateur n'est-ce pas? –

0

1) peut-être un peu plus de code serait utile. Créez-vous un nouveau thread et mettez le timer sur ce thread?

2) Avez-vous essayé d'utiliser ManualResetEvent (.WaitOne() et .Set() à la place?)

3) Dans votre cas, si Invoke est nécessaire, vous réutilisez appelez à nouveau votre événement. Confondre ...

4) Êtes-vous censé attendre que l'autre thread soit terminé? Puis Thread.Join()?

+0

1) Timers déclenchent des événements sur un nouveau fil toujours. 2) Je pense que je vais avoir le même verrou avec ManualResetEvent 3) Autant que je sache, c'est la façon normale de gérer les threads non UI qui ont besoin de mettre à jour les éléments de l'interface utilisateur. 4) N'est pas un thread que j'ai créé, c'est le thread interne que le timer crée. –

Questions connexes