2009-09-28 5 views
0

J'ai remarqué que AutoResetEvent gèle complètement la boucle de message (parfois) quand il est au milieu d'un appel WaitOne(), bloquant même le message de signal.Objets AutoResetEvent et COM

IE:

  1. (IU) Nouveau fil donné naissance à
  2. (UI) Code appelle WaitOne(); délai d'attente: 10s
  3. (T2) Fil ouvre dispositif, les appels Set()
  4. (UI) blocs WaitOne boucle messages
  5. (UI) délai de WaitOne écoulé, l'exécution de code continue
  6. (UI) Fenêtre principale reçoit le signal et continue (mais WaitOne a échoué)

Des idées?

EDIT: ajout d'UI/T2 pour spécifier les unités d'exécution. En outre, j'essaie de transformer une bibliothèque tierce en synchrone. L'ouverture de périphériques implique un appel Open() qui à son tour engendre un événement OpenOK ou OpenFailed, j'essaye de faire un appel booléen Open() qui renvoie true/false en fonction de l'événement engendré.

+0

Pourriez-vous préfixer avec quel thread chaque opération s'exécute (peut-être utiliser UI, T1, T2, etc) dans les étapes ci-dessus. C'est un peu plus difficile à suivre quel fil est ce qui dans votre description. – SwDevMan81

+0

En outre, si vous le souhaitez, vous pouvez définir l'état de l'AutoResetEvent à signaler lorsque vous le créez de sorte que vous n'arrêtez pas le premier appel (si c'est ce que vous voulez) -> AutoResetEvent e = AutoResetEvent (true); – SwDevMan81

+0

Définir "ouvre l'appareil". Vous pouvez vous assurer que l'ouverture du périphérique ne dépend pas des messages traités par la boucle de message. –

Répondre

1

... efficacement bloquant même le message du signal.

Vous ne pouvez pas "bloquer l'envoi d'un signal", vous pouvez seulement empêcher l'autre thread d'arriver au réglage de l'événement. Les poignées d'attente ne nécessitent aucune pompe à message. La seule chose à laquelle je peux penser est que l'objet COM en question est lié au thread de l'interface utilisateur. L'accès à l'objet COM peut être tenté d'invoquer de retour de T2 vers le thread d'interface utilisateur qui attend que T2 fasse quelque chose (interblocage). Pour voir si c'est effectivement le problème assurez-vous que vous ne créez pas ou n'accédez pas à l'objet COM sur le thread UI.

+0

Et si j'avais * * pour le créer sur le fil de l'interface utilisateur ? Que recommanderiez-vous? De même, comment le créeriez-vous sur un autre fil? –

+0

Coup le des options ... réponse facile est d'utiliser seulement le thread UI et un événement Timer pour interroger l'objet COM jusqu'à la fin. –

0

Ceci est le résultat d'une condition de concurrence. Le problème est que l'étape 3 peut se produire avant l'étape 2, car ils sont sur des threads différents. Parce que vous utilisez un AutoResetEvent, au moment où WaitOne est appelé, l'événement est déjà réinitialisé.

En raison de ce problème, lorsque cela est possible, j'essaie généralement d'éviter AutoResetEvents en faveur de ManualResetEvents.

L'ordre des événements avec un ManualResetEvent serait (j'ai énuméré 2 cas comme 2a et 2b pour démontrer que leur ordre de fonctionnement ne soit pas garantie):

  1. une nouvelle discussion Engendré
  2. a. Le thread d'origine appelle WaitOne(); b. Nouveaux appels de thread Set();
  3. Le fil d'origine se réveille.
  4. Appels de threads d'origine Reset();
+0

Ce n'est pas une condition de course. Dans le cas particulier que j'ai testé, ce n'est pas immédiat - cela prend quelques secondes. De toute façon, comment cela changerait-il avec ManualResetEvent au lieu de Auto? –

+0

Le retard ne contre-indique pas la condition de concurrence que je vois. ManualResetEvents reste défini jusqu'à ce qu'il soit explicitement réinitialisé. Votre AutoResetEvent se réinitialise avant l'appel de WaitOne. C'est pourquoi le WaitOne n'est jamais déclenché. –

+0

Le même problème se produit avec ManualResetEvent. Je sais à coup sûr que la pompe à messages est bloquée aussi, mais je ne sais pas comment gérer cela. :( –