D'accord, cette question ne concerne donc pas exactement la gestion de thread ... Eh bien, en quelque sorte. Je cherche différentes solutions à cette configuration. J'ai quelques idées, mais je cherche des solutions pouvant satisfaire le problème. Et pesera les avantages et les inconvénients pour mettre en œuvre le meilleur. P>
Voici la situation. P>
J'ai une application de gestionnaire qui apparaîtra un threads. Ce fil fonctionnera et gérera en permanence la communication série avec des cartes connectées au système via USB. L'application Manager facilite la communication entre d'autres applications exécutées sur le système et ce fil. Le fil doit vraiment effectuer deux choses: p>
Mon design initial était simple et fonctionne. J'utilise une file d'attente et un mutex pour responsable de la communication. Donc, la logique du fil est la suivante: P>
Le problème est que je n'ai pas considéré l'utilisation du processeur. 99,9% du temps où mon thread ne traite rien et ne vient de sucer le pouvoir. Je dois mettre en œuvre un moyen de dormir ce fil jusqu'à ce qu'il ait du travail à faire. Donc quelques idées: p>
Utilisez SELECT () à bloquer. Cela peut bloquer en fonction de la minuterie que j'ai besoin d'utiliser et je pourrais modifier la mise en œuvre de la messagerie en file d'attente en prise. Messagerie. Donc, à la place, le fil ouvrirait une prise client à la gestionnaire et le gestionnaire transmettraient les messages sur la prise à la fil. Puis sélectionnez () dormirait jusqu'à ce qu'il y ait une activité sur la FD ou ma minuterie était en place. p> blockQuote>
pro: exactement la fonctionnalité dont j'ai besoin. p>
CON: ne pas être des sockets un peu lourd pour la communication à un thread où vous partagez déjà la mémoire? p>
Utilisez un système de signal. (Quelqu'un de plus bien informé à Linux peut pipe ici avec un exemple de mise en œuvre ... Je ne suis pas sûr de savoir exactement comment faites-le.) Mais le fil pourrait dormir pendant la durée de la minuterie, et Réveillez-vous pour traiter si un signal a été reçu du gestionnaire. P> blockQuote>
pro: maintient la mise en œuvre actuelle à l'aide de la mémoire partagée p>
Con: Je ne sais pas comment mettre en œuvre. Y a-t-il une fonction comme SELECT () qui fonctionne avec des signaux au lieu de FDS? P>
potentiellement un mutex. Je pourrais bloquer jusqu'à ce qu'un mutex soit affecté par le gestionnaire. P> blockQuote>
Pro: partage encore la mémoire p>
Con: Peut-être besoin de déplacer le traitement du minuteur au gestionnaire et qui n'est vraiment pas une option car il a d'autres minuteries et un travail critique à effectuer. P>
S'il vous plaît recommander et n'hésitez pas à critiquer. Je suis ouvert à toutes les options efficaces. Veuillez noter que cela s'exécute sur un système intégré, l'utilisation des ressources est donc essentielle. P>
5 Réponses :
Demandez à chaque fil d'attente sur une file d'attente de producteur d'intrants avec un délai d'attente. Si les temps d'attente de la file d'attente, sondez la liaison série, sinon traiter la commande reçue sur la file d'attente. Pour former une file d'attente appropriée à partir de zéro, vous avez besoin d'une file d'attente (que vous avez déjà), un mutex pour protéger les pointeurs / index de la file d'attente (que vous avez déjà) et un sémaphore, initialisé à 0, avec une attente ( délai d'attente) fonction. Pour envoyer une demande du fil, verrouillez le mutex, appuyez sur la requête, déverrouillez le mutex, signaler le sémaphore. Dans le fil, attendez sur le sémaphore, si vous attendez sans délai, verrouillez le mutex, POP La demande (car il y en aura toujours un), déverrouillez le mutex et traiter la demande reçue. Si la SEMA WAIT revient avec un délai d'attente, sondez la liaison série. Lorsque fait, boucle pour attendre à nouveau sur le sémaphore. P>
Pour varier le délai d'attente, envoyez un message sur le thread avec la commande 'echangewaitInterval', (disons :) et le nouvel intervalle de délai d'attente à utiliser pour les attentes ultérieures. P>
Basculez sur les files d'attente de message POSIX au lieu de votre propre. mq_timédreceive code> reviendra si le gestionnaire publie une demande. Si cela tente, vous devez faire votre sondage de minuterie. La synchronisation et le blocage sont déjà emballés. P>
Un peu trop lourd, les sémaphores sont un peu plus simples.
L'outil classique pour gérer de telles situations sont des sémaphores et non des mutiles ou des variables de condition. Pensez à eux comme des jetons passés du manager au fil. P>
Le thread pourrait utiliser méfiez-vous pour capturer les retours d'erreur de SEM_TIMEDWAIT code> pour vous assurer de vous réveiller de temps en temps pour vérifier les données. P>
SEM _ code> fonctionne bien, ils sont interruptibles. Donc, vous pouvez avoir un peu plus de réveil que vous ne le pensez. P>
Un couple de sémaphore répond ici, alors répondra à eux tous ici. Utiliserait un sémaphore comme une minuterie pour se réveiller et vérifier que les données soient plus efficaces que de bloquer avec sélectionner () et recevoir les données sur une prise? D'une part, j'utilise une mémoire partagée au lieu de RECV (), mais de l'autre, si je ne reçois jamais de demande d'une autre application. Je traite sans raison.
Comme vous décrivez votre problème, le fait que votre fil ne dort pas est vraiment significatif. Cela signifie que si vous le tournez, votre fil ne fonctionne pas beaucoup de travail par rapport à cela. Donc, si vous maîtrisez ce problème "sommeil", quelle solution que vous prenez aura beaucoup d'impact sur le travail global (cycles de processeur) utilisés par le fil. Les différences sont alors dans (1) commodité, ce qui est programmé et maintenu la latence la plus facile (2). Pour les deux, je pense que les sémaphores gagnent.
Les attentes du sémaphore bloquent. Si l'attente () n'est pas encore expirée et que le sémaphore n'est pas encore signalé et son décompte interne est zéro, aucun processeur n'est utilisé du tout. L'attente SEM (Timeout) ne reviendra pas avant que d'une condition ou de l'autre soit satisfaite. Si les temps d'attente sont sortis, la cuve sera courante une fois. Si le sémaphore est signalé 15 fois par les messages de file d'attente du gestionnaire, le thread fonctionnera ensuite 15 fois et traitera tous les 15 et pas plus.
OH - Notez bien le commentaire de Jens sur les réveilles d'interruption. Sur le système d'exploitation défectueux qui supportent cette "fonctionnalité de réveil parasite", vous devez vérifier :(
@Martinjames, «parasites WakeUps» ne sont pas une faute mais prévu en tant que telle. Cela permet d'écrire un code de bas niveau qui réagit sur les interruptions.
Les pilotes Windows @jensGustedt sont des indicateurs de bas niveau qui réagissent sur des interruptions, des sémaphores / événements Windows / etc. permettent la communication avec ce code et entre les threads. Différence - il n'y a jamais de réveil parasite, jamais. Nous devrons peut-être accepter de différer à ce sujet, mais je considère que tout réveil faux faux sur un signal qui n'a pas été signalé comme un bogue grave qui, bien qu'il y ait une solution de contournement de l'espace utilisateur, aurait dû être traitée dans le noyau où tout De telles «fonctionnalités» devraient rester. Dijkstra se retournerait dans sa tombe ..
@Martinjames, cette question est clairement étiquetée sous la forme de Linux, c'est-à-dire un système POSIX. Je ne sais pas grand chose à propos de Windows, et en particulier à cet égard aux sémaphores, et j'espère que jamais ne sera jamais tenté de faire face à un système d'exploitation que je ne connais pas grand chose. Dans POSIX SEM_T CODE> est conçu exprès pour être utilisable dans les gestionnaires de signaux, il s'agit d'un outil de faible niveau par conception. Cela n'a rien à voir avec le système d'exploitation "défectueux" et certainement rien à voir avec Dijstra. Dans tout ce que je considère votre remarque assez inappropriée.
Je prends ton point et je ne voulais pas être offensant ou inapproprié. OTOH, Windows, RTOS, FAXEROS, RMX, CTL, OS2, ETC ET. Vous n'avez pas de réveil parasite. Seules les varants U ** x semblent avoir cette fonctionnalité.
L'approche classique Pthreads de ce type serait d'avoir votre bloc de fil dans pthread_cond_wait () code> jusqu'à ce que le thread du gestionnaire met un message dans la file d'attente et signale la variable de condition. Dans ce cas, se réveiller de manière opportune pour interroger les dispositifs de série, utilisez
pthread_cond_timpedwait () code> à la place. P>
Essayez quelque chose comme ceci, à l'aide de sémaphores: Vous pouvez remplacer sem_wait code> avec
SEM_TIMEDWAIT code> Si vous avez besoin d'un délai d'attente. p> p>
Pourquoi ne pas utiliser une variable conditionnelle lorsque vous devez attendre un événement? Le fil est effectivement mis en veille jusqu'à ce que la variable soit signalée par un autre fil.
Je pourrais absolument, mais le but est que je ne veux rien traiter. Je ne veux pas vérifier à plusieurs reprises la valeur d'une variable qui va changer une fois par minute. C'est beaucoup de frais généraux. Je veux que le fil dorme de manière à ce qu'il abandonne le temps de la CPU.
Assurez-vous d'éviter ceci: pubs. opengroup.org/onlinepubs/009604599/fonctions/.../a>
@Tudor merci, je n'étais pas au courant de _timpedwait. Cela pourrait être une bonne solution car il n'aurait pas besoin de recoder le responsable de la communication. Je vais lire dessus.
Comment la minuterie est-elle mise en œuvre? Est-il externe au thread du travailleur (comme un autre thread ou le noyau avec
Sétititimer code> ou
Timer_create code>), ou le fil-ouvrier fait-il simplement faire son propre chronométrage?
@pilcrow Le fil est-il propre à la tenue de temps. Comme le gestionnaire a beaucoup à faire et que ses propres minuteries se produisent. Il est logique que le fil gère son propre timing.
@njozwiak: Eh bien, il existe d'autres approches correctes et efficaces qui pourraient avoir un sens aussi. :) Toutefois, extension de votre file d'attente pour prendre en charge une opération "chronoméue" via
pthread_cond_timpedwait code> - en essence Martin James ' Réponse - a du sens pour vous.