Question

J'écris une application qui bloque l'entrée de deux istreams .

La lecture de istream est un appel synchrone (bloquant). J'ai donc décidé de créer deux Boost :: thread pour effectuer la lecture.

L'une ou l'autre de ces discussions peut atteindre la "fin". (sur la base de certaines contributions reçues), et une fois la "fin" est atteint, les deux flux d’entrée cessent de recevoir. Malheureusement, je ne peux pas savoir qui le fera.

Par conséquent, je ne peux pas join () sur les deux threads, car un seul thread (qui ne peut pas être prédéterminé) retournera (débloquera).

Je dois forcer l’autre à sortir, mais il est bloqué dans l’attente d’une entrée; il ne peut donc pas décider lui-même qu’il est temps de revenir (variables de condition ou non).

S'agit-il d'un moyen de:

  • Envoyez un signal à un boost :: thread ou
  • Forcer un istream à "échouer" ou
  • Kill a Boost :: thread?

Remarque:

  • L'un des istreams est cin
  • J'essaie de redémarrer le processus. Je ne peux donc pas fermer les flux d'entrée de manière à empêcher leur remise à zéro.

Modifier:

  • Je sais quand "& end; end " est atteint, et je sais quel thread a été terminé avec succès et lequel doit être tué. C’est une tuerie que je dois comprendre (ou une stratégie différente pour lire dans un istream).
  • J'ai besoin des deux threads pour quitter et nettoyer correctement: (

Merci!

Était-ce utile?

La solution

Je ne pense pas qu'il y ait un moyen de le faire sur plusieurs plates-formes, mais pthread_cancel devrait être ce que vous recherchez. Avec un fil de discussion, vous pouvez obtenir le native_handle à partir d'un thread et appelez pthread_cancel dessus.

De plus, un meilleur moyen pourrait être d'utiliser le boost asio équivaut à un appel de sélection sur plusieurs fichiers. De cette façon, un thread sera bloqué dans l'attente de l'entrée, mais cela pourrait provenir de l'un ou l'autre des flux d'entrée. Je ne sais pas à quel point il est facile de faire quelque chose comme ça avec iostreams.

Autres conseils

Oui, il y en a!

boost :: thread :: terminate () fera le travail selon vos spécifications.

Le thread ciblé générera une exception. En supposant que cela n’a pas été capturé, la pile se déroulera correctement en détruisant toutes les ressources et en mettant fin à l’exécution du thread.

La résiliation n'est pas instantanée. (De toute façon, le mauvais thread est en cours d’exécution.)

Cela se produit dans des conditions prédéfinies - le plus pratique pour vous serait probablement d'appeler boost :: this_thread :: sleep (); , ce que vous pourriez faire faire périodiquement à ce thread.

Si un thread boost bloque une opération d'E / S (par exemple, cin >> quel que soit ), boost :: thread :: terminate () ne tuera pas le fil. cin e / s n'est pas un point de terminaison valide. Catch 22.

Eh bien, sur Linux, j'utilise pthread_signal (SIGUSR1), car il interrompt le blocage des entrées / sorties. Il n’existe pas d’appel sur Windows tel que je l’ai découvert lors du portage de mon code. Seul un appel de lecture obsolète en lecture. Dans Windows, vous devez définir explicitement un événement qui interrompra votre appel bloquant. Donc, il n’existe pas (AFAIK) un moyen générique d’interrompre le blocage des E / S.

La conception boost.thread gère cela en gérant des points d'interruption bien identifiés. Je ne sais pas bien boost.asio et il semble que tu ne veuilles pas compter dessus de toute façon. Si vous ne voulez pas refactoriser pour utiliser le paradigme non bloquant, vous pouvez utiliser quelque chose entre non bloquant (scrutation) et blocage des entrées-sorties. C’est faire quelque chose comme (pseudo-code?):

while(!stopped && !interrupted)
{
    io.blockingCall(timeout);
    if(!stopped && !interrupted)
    {
        doSomething();
    }
}

Ensuite, vous interrompez vos deux threads et les rejoignez ...

Peut-être est-ce plus simple dans votre cas? Si vous avez un thread principal qui sait qu'un thread est terminé, vous devez simplement fermer l'IO de l'autre thread?

Modifier: En passant, je suis intéressé par la solution finale que vous avez ...

J'ai moi-même eu un problème similaire et je suis parvenu à cette solution, ce que certains lecteurs de cette question pourraient trouver utile:

En supposant que vous utilisez une variable de condition avec une commande wait (), il est important de savoir que dans Boost, l'instruction wait () est un point d'interruption naturel. Il suffit donc de placer un bloc try / catch autour du code avec l'instruction wait et de permettre à la fonction de se terminer normalement dans votre bloc catch.

Maintenant, si vous avez un conteneur avec vos pointeurs de thread, parcourez-le et appelez interrupt () sur chaque thread, suivi de join ().

Tous vos threads vont maintenant se terminer normalement et tout nettoyage de la mémoire lié à Boost doit fonctionner correctement.

Plutôt que d'essayer de tuer votre thread, vous pouvez toujours essayer de le rejoindre, et s'il échoue, vous rejoignez l'autre. (En supposant que vous pourrez toujours rejoindre au moins un de vos deux threads).

En résumé: vous recherchez le fonction timed_join .

Toutefois, si vous souhaitez consulter la bonne réponse, utilisez io non bloquant avec des délais d’attente. Vous permettant d'obtenir la structure de flux de io synchrone, avec le non blocage de io asynchrone.

Vous parlez de lire comme un istream, mais un istream n’est qu’une interface. pour stdin, vous pouvez simplement fermer le descripteur de fichier stdin pour interrompre la lecture. Pour ce qui est de l’autre, cela dépend de l’endroit où on lit ...

Il semble que les discussions ne vous aident pas à faire ce que vous voulez d'une manière simple. Si Boost.Asio ne vous convient pas, utilisez select () .

L'idée est d'obtenir deux descripteurs de fichier et d'utiliser select () pour vous indiquer lequel d'entre eux a une entrée disponible. Le descripteur de fichier pour cin est généralement STDIN_FILENO ; comment obtenir l’autre dépend de vos spécificités (s’il s’agit d’un fichier, il suffit de le open () au lieu d’utiliser ifstream ).

Appelez select () dans une boucle pour savoir quelle entrée lire, et quand vous voulez vous arrêter, sortez de la boucle.

Sous Windows, utilisez QueueUserAPC pour mettre en file d'attente un proc qui lève une exception. Cette approche fonctionne bien pour moi.

TOUJOURS : je viens de constater que les mutex boost, etc., ne sont pas "alertables". sur win32, QueueUserAPC ne peut donc pas les interrompre.

Très tard, mais sous Windows (et ses précurseurs tels que VMS ou RSX pour ceux qui se souviennent de ce genre de choses), j'utiliserais quelque chose comme ReadFileEx avec une routine d'achèvement signalant la fin de l'opération et CancelIO si la lecture doit être annulée plus tôt. .

Linux / BSD a une API sous-jacente totalement différente qui n’est pas aussi flexible. Utiliser pthread_kill pour envoyer un signal fonctionne pour moi, cela arrêtera l'opération de lecture / ouverture.

Cela vaut la peine d'implémenter un code différent dans cette zone pour chaque plate-forme, à mon humble avis.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top