2010-03-23 16 views
0

Je me bats avec la programmation multi-thread ...partage des ressources Discussion

J'ai une application qui parle à un dispositif externe via un CAN au module USB . J'ai l'application parler au bus CAN très bien, mais il est nécessaire pour l'application de transmettre un « battement de coeur » message à chaque seconde.

Cela semble être le moment idéal pour utiliser des threads, donc j'ai créé un thread qui se réveille toutes les secondes et envoie le battement de coeur. Le problème que je suis ayant partage l'interface de bus CAN. Le signal de présence doit uniquement être envoyé lorsque le bus est inactif. Comment partager la ressource?

Voici le code pseudo montrant ce que j'ai jusqu'à présent:

TMainThread 
{ 
    Init: 
     CanBusApi =new TCanBusApi; 
     MutexMain =CreateMutex("CanBusApiMutexName"); 

     HeartbeatThread =new THeartbeatThread(CanBusApi); 

    Execution: 
     WaitForSingleObject(MutexMain); 
     CanBusApi->DoSomething(); 
     ReleaseMutex(MutexMain); 
} 

THeartbeatThread(CanBusApi) 
{ 
    Init: 
     MutexHeart =CreateMutex("CanBusApiMutexName"); 

    Execution: 
     Sleep(1000); 
     WaitForSingleObject(MutexHeart); 
     CanBusApi->DoHeartBeat(); 
     ReleaseMutex(MutexHeart); 
} 

Le problème que je vois est que quand DoHeartBeat est appelée, elle provoque le thread principal bloquer en attendant MutexMain comme prévu, mais DoHeartBeat s'arrête également. DoHeartBeat ne se termine qu'après l'expiration du délai de WaitForSingleObject (MutexMain).

Est-ce que DoHeartBeat s'exécute dans le contexte MainThread ou HeartBeatThread? Il semble être en cours d'exécution dans MainThread.

Qu'est-ce que je fais mal? Y a-t-il un meilleur moyen?

Merci, David

+0

David, vous avez raison. C'était de ma faute. –

Répondre

0

je soupçonne que l'API de bus CAN est mono-thread sous les couvertures. Il peut s'agir de marshaling votre demande DoHeartBeat() à partir de votre deuxième thread dans le thread principal. Dans ce cas, il n'y aurait aucun moyen de réussir puisque votre thread principal est bloqué. Vous pouvez résoudre ce problème essentiellement de deux façons: (1) envoyer un message au thread principal, en lui disant de faire le rythme cardiaque, plutôt que de le faire sur le deuxième thread; ou (2) utilisez une minuterie sur le fil principal pour votre rythme cardiaque au lieu d'un second fil. (Je pense que multithreading est surpuissant pour ce problème particulier.)

+0

Je pense qu'il est vrai que l'API de bus CAN est mono-thread interne et agit-elle comme DoHeartBeat() est exécuté dans le contexte de MainThread, mais je ne suis pas sûr de savoir comment le prouver. Est-il généralement vrai que les méthodes objet s'exécutent dans le thread qui a créé l'objet même lorsqu'il est appelé depuis un thread différent? – David

+0

Ma motivation pour utiliser les threads est de simplifier ma machine à états de processus. Avec le battement de cœur géré dans un thread séparé, ma machine d'état peut ignorer les exigences strictes de synchronisation du rythme cardiaque.Si j'utilise un seul thread, je dois créer un mécanisme pour savoir quand le bus est utilisé, ce qui est exactement ce que fait un mutex. Il semblait préférable de ne pas ré-implémenter ce concept. – David

+0

Lorsque vous appelez une méthode objet, la méthode s'exécute dans le contexte du thread qui l'a appelée, mais cela ne dit rien de ce que la méthode * fera *. Si l'API du bus CAN est implémentée à l'aide d'un serveur COM threadé, alors sous les couvertures, DoHeartBeat() enverra un message de fenêtre à votre thread principal et lui demandera de faire le travail. Vous devrez faire des recherches si c'est le cas. La bonne nouvelle est que si l'API utilise un serveur COM thread-thread, alors vous n'avez pas besoin du mutex. –

0

D'abord, relisez les spécifications sur le rythme cardiaque. Est-il dire qu'un message de rythme cardiaque réel doit être reçu à chaque seconde, ou est-il nécessaire que certains message soit reçu à chaque seconde, et qu'un rythme cardiaque doit être utilisé si aucun autre message sont en vol? La présence de données sur le canal est une preuve de facto que le canal de communication est vivant, donc aucun message de battement de cœur spécifique ne devrait être requis.

Si un message de rythme cardiaque réel est nécessaire, et il est nécessaire à chaque seconde, dans le code ci-dessus il devrait y avoir qu'un seul mutex et les deux fils ont besoin de partager. Le code tel qu'il est écrit crée deux mutex distincts, donc aucun ne bloquera réellement. Vous allez vous retrouver avec une collision sur le canal et Bad Things Will Happen dans CanBusApi. Rendez MainMutex visible une variable globale/classe et faites-la référencer par les deux threads.

+0

Le battement de cœur est requis toutes les secondes, quel que soit le trafic de bus. Il maintient le périphérique de réception en "mode Test". – David

+0

Je travaille dans MS Windows. Je crois comprendre que CreateMutex() ne crée un nouveau mutex que s'il en trouve un avec le nom spécifié. Sinon, il renvoie un handle au mutex existant. Est-ce que je me trompe? – David

+0

Non, vous avez raison. Appeler CreateMutex deux fois avec le même nom renvoie deux handles au même objet. –