2010-10-21 15 views
1

J'ai créé deux classes. Un pour la lecture d'entrée (à travers un objet istream) et l'analyse et l'autre pour le traitement de la sortie de l'analyseur.
Il existe une instance de chacun d'entre eux.
J'ai l'analyseur s'exécutant dans une boucle appelant istream :: get(), puis créant des commandes pour le second objet basé sur l'entrée. Ces commandes sont ensuite placées sur une file d'attente que le second objet traite dans un thread séparé.
Maintenant, il est tout à fait évident que j'ai finalement besoin d'être en mesure d'envoyer une commande "Quitter". Ici, le problème se pose: La commande "Quitter" doit également mettre fin à la boucle d'analyse, mais je ne trouve pas un moyen de signaler à l'analyseur qu'il doit quitter car il est intercepté par istream :: get().
Je voudrais un moyen de le réveiller de cette méthode, mais je ne trouve pas ...
J'ai pensé écrire une sorte de "séquence de terminaison" à l'objet istream (qui est dans ce cas cin) en créant un objet ostream de istream :: rdbuf(). Mais cela ne fonctionne pas - Le badbit est défini après la tentative d'écriture dans le tampon.
Dans une autre question à StackOverflow j'ai vu la classe asio de la bibliothèque Boost mentionnée, mais je préfère ne pas dépendre de bibliothèques tierces.
Existe-t-il un moyen de réveiller le thread d'istream :: get() - c'est-à-dire d'écrire dans le buffer istream (peut-être en supposant qu'il s'agit de cin) dans le programme?
Une autre approche serait de tuer le fil que je pourrais trouver acceptable, car il n'y a pas de nettoyage nécessaire à cet endroit spécifique. Mais comment cela peut-il se faire? (Je compte sur une implémentation de threads POSIX)Comment libérer un thread istream bloqué

Répondre

1

Vous devrez compter sur autre chose que les classes standard iostream, parce qu'ils ne fournissent pas select() le comportement de style.

En outre, la suppression du thread est impossible avec POSIX (et complètement cassé dans Windows). Vous pouvez émettre une demande d'annulation via pthread_cancel(), mais dans votre cas, il peut être bloqué dans un appel système non annulable. Particulièrement intéressant pour vous, read() peut être annulé ou non, selon l'environnement. At least one environment indique qu'un point d'annulation peut se produire dans read(), mais il est admis qu'il s'agit d'une couche Windows POSIX. En outre, Mac OS X, aussi récemment que Leopard 10.5.1, avait une implémentation read() cassée en ce qui concerne l'annulabilité. Une fois cet obstacle franchi, vous devez également considérer le uneasy relationship entre les destructeurs C++ et pthread_cancel. Tous les environnements ne garantissent pas que les destructeurs seront appelés, vous devez donc être extrêmement prudent lorsque vous utilisez pthread_cancel dans le code C++. En bref, pour les E/S interruptibles, utilisez des E/S de bas niveau et select(): un f pour les E/S, un second fd (créé par pipe()) pour la signalisation.Ou, si vous êtes courageux, utilisez AIO, mais vous êtes probablement mieux d'utiliser une interface de haut niveau telle que Boost.Asio.

+0

J'ai effectivement essayé l'appel pthread_cancel() mais comme vous l'avez dit, cela ne fonctionne pas du tout ou est assez peu fiable. Les destructeurs n'auraient probablement pas posé de problème, puisque j'aurais pu mettre le code de nettoyage dans un autre thread. Merci pour la référence à select() cependant. Je ne le savais pas. – iolo

1

Une chance que cela est implémenté dans .NET? - Si oui, jetez un oeil au Reactive Framework. Il fournit une manière très élégante de gérer flux et en particulier en les annulant à la volée. - En plus de cela, vous obtenez une bibliothèque très extensible d'extension Linq pour toutes sortes de choses, comme Buffering, Memoization, Zip ect ..

Nous l'utilisons beaucoup pour transformer (et analyser), modéliser des flux Les données.

Jeff de l'équipe Reative a un Couble de blogs sur les belles Streaming and Reative here:

+0

Eh bien ... je suppose que j'ai oublié ce point. ;-) Je le fais sur un mac mais j'aimerais que le code soit portable. Ainsi je voudrais utiliser seulement la bibliothèque standard ou n'importe quels appels de posix. – iolo