9
votes

Existe-t-il un moyen d'obtenir une insertion / extraction de flux non verrouillable sur basical_iostream dans Windows?

Je suis un développeur C ++ qui a principalement programmé sur Solaris et Linux jusqu'à récemment, lorsque j'ai été obligé de créer une application destinée à Windows.

J'utilise une conception de communication basée sur le flux d'E / S C ++ soutenu par la prise TCP. La conception est basée sur un seul fil de lecture en continu du flux (la plupart du temps bloqué dans la prise en attente en attente de données) tandis que d'autres threads envoient le même flux (synchronisé par mutex).

lors du déplacement Pour Windows, j'ai été élu pour utiliser le boost :: Asio :: IP :: TCP :: iostream pour implémenter le flux de socket. J'ai été consterné pour constater que la conception multithreadée ci-dessus a entraîné une impasse sur Windows. Il semble que l'opérateur << (STD :: basic_ostream <...>, std :: basique_string <...>) déclare une "sentinelle" qui verrouille le flux entier pour une entrée et une sortie Opérations. Étant donné que mon fil de lecture attend toujours sur le flux, envoyez des opérations à partir d'une autre impasse de threads lorsque cette senture est créée.

Voici la partie pertinente de la pile d'appels pendant l'opérateur << et la construction sentinelle: xxx

i irait bien si les composants Istream et Otstream étaient Verrouillé séparément, mais ce n'est pas le cas.

existe une alternance de mise en œuvre des opérateurs de flux que je peux utiliser? Puis-je diriger ne pas verrouiller? Devrais-je mettre en œuvre le mien (pas sûr de savoir comment faire cela)?

Toute suggestion serait appréciée.

(plate-forme est Windows 32- et 64 bits. Comportement observé avec Visual Studio 2003 pro et 2008 express)


1 commentaires

+1 Grande question, bien formulée. Pitié je n'ai pas de réponse pour vous!


5 Réponses :


0
votes

Peut-être que vous pourriez implémenter une couche de verrouillage vous-même? C'est-à-dire, j'ai un istream distinct et ostream que vous vous verrouillez-vous quand ils sont invoqués. Périodiquement, vérifiez si les deux sont déverrouillés, puis lus d'un dans l'autre.


0 commentaires

0
votes

Avez-vous explicitement affleuré le flux après avoir écrit? Ce blog Publier implique que vos données puissent simplement être "coincé" dans le tampon. Si c'est vrai, alors peut-être que vous semblez peut-être une impasse car il n'y a pas encore de disponible pour la lecture. Ajouter flux << std :: flush à la fin de vos opérations d'envoi.

Une solution alternative (bien que moins efficace) suggérée par le blog Publier consiste à éteindre la mémoire tampon de sortie du flux: xxx


1 commentaires

En fait, je rince le flux aux limites des messages, mais ce n'est pas le problème ici. L'autre extrémité de cette connexion n'est pas bloquée en attente de données. Au lieu de cela, deux threads sont sans égoutts sur la «sentinelle» iostream que les flux Windows définissent. Merci pour votre considération.



1
votes

Selon la documentation Boost [1], l'utilisation de deux threads accédant à l'objet un objet sans mutex est "dangereux". Juste parce que cela fonctionnait sur les plates-formes UNIX ne garantit que cela fonctionnera sur la plate-forme Windows.

Donc, vos options sont:

  1. Réécrivez votre code afin que vos fils n'accumulent pas l'objet simultanément
  2. Patch la bibliothèque de boost et envoyer les modifications dos
  3. Demandez à Chris vraiment bien s'il fera les modifications de la plate-forme Windows

    [1] http: //www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/overview/core/threads.html


4 commentaires

Merci pour l'entrée. Juste pour clarifier - cette question concerne spécifiquement la mise en œuvre visuelle du studio du modèle BASIC_OSTREAM, qui étend une classe de contrôle de verrouillage et d'erreur appelée Sentry. Ce n'est pas un problème avec la Boost :: Asio Bibliothèque (bien que votre référence soit une bonne chose à noter).


Avez-vous besoin de convertir de TCP :: iostream à la STD de Visual Studio :: iostream? Vous pourriez avoir plus de chance si vous le gardez TCP :: iostream tout le chemin.


Je n'avais pas pensé qu'à travers tout le chemin ... J'écris habituellement ma classe in / out (lecture / écriture, etc.) en termes de dénominateur commun le plus bas (Istream / Otstream). Merci pour la nourriture de pensée.


Il suffit de voir cet article, qui relie à une autre question Stackoverflow Question: DobbscodeTalk.com/ ...



1
votes

Cette question a languie pendant assez longtemps. Je vais signaler ce que j'ai fini par faire, même s'il y a une chance, je serai déraciné.

J'avais déjà déterminé que le problème était que deux threads arrivaient à une impasse tout en essayant d'accéder à un objet iOSTream dans des opérations de lecture et d'écriture distinctes. Je pouvais voir que la mise en œuvre de la mise en œuvre de Studio Visual Studio d'insertion de flux de chaîne et d'exploitants d'extraction a déclaré une sentinelle, qui verrouillait le tampon de flux associé au flux étant exploité.

Je savais que, pour le flux en question pour cette impasse, la mise en œuvre du tampon de flux a été boost :: Asio :: basique_socket_streambuf. J'ai inspecté la mise en œuvre pour voir que des opérations de lecture et d'écriture (sous le débit et débordement) fonctionnent réellement sur différents tampons (gagnez vs. Met).

avec ce qui précède vérifié, j'ai choisi de simplement contourner le verrouillage de cette application. . Pour ce faire, j'ai utilisé des définitions de pré-processeur spécifiques au projet pour exclure le code de verrouillage de la mise en œuvre de base_istribution de la sentinelle de verrouillage: xxx

upside:

  • ça marche
  • Seul mon projet (avec les définitions appropriées) est affecté

    inconvénient:

    • se sent un petit hacky
    • Chaque plate-forme où elle est construite aura besoin de cette modification

      Je prévois d'atténuer le dernier point en le documentant fort dans la documentation du code et du projet.

      Je me rends compte qu'il peut y avoir une solution plus élégante à cela, mais dans l'intérêt de l'opportunité, j'ai choisi une solution directe après la diligence raisonnable de comprendre les impacts.


0 commentaires

0
votes

Je sais que c'est une vieille question ... Mais je devais juste faire cela moi-même!

Ma situation était plus compliquée car c'était mon propre Streambuf, mais vous pouvez résoudre ce problème en faisant: P >

std::ostream &operator<<(std::ostream &x, std::string &y)
{
  x.rdbuf()->_Unlock();
  x << y.c_str();
}


0 commentaires