110 votes

Est cout synchronisé/thread-safe?

En général, je suppose que les flux ne sont pas synchronisés, c'est à l'utilisateur de faire de verrouillage. Cependant, faire des choses comme cout obtenir un traitement spécial dans la bibliothèque standard?

C'est, si plusieurs threads en écriture à l' cout peuvent-ils corrompus de l' cout objet? Je comprends que, même si synchronisé vous souhaitez toujours arriver au hasard entrelacés de sortie, mais est-ce que l'entrelacement de la garantie. Ce qui est, est-il sécuritaire d'utiliser cout à partir de plusieurs threads?

Est ce vendeur à charge? Ce n'gcc?


Important: Veuillez fournir une sorte de référence pour votre réponse si vous dites "oui" car j'ai besoin d'une sorte de preuve de cela.

Ma préoccupation est pas non plus sur le système sous-jacent appels, ceux qui sont beaux, mais le flux d'ajouter une couche de mise en mémoire tampon sur le dessus.

103voto

R. Martinho Fernandes Points 96873

Le C++03 standard, ne rien dire à ce sujet. Lorsque vous n'avez aucune garantie sur le thread de sécurité de quelque chose, vous devez le traiter comme pas thread-safe.

Ici un intérêt particulier est le fait qu' cout est mis en mémoire tampon. Même si l'appel à l' write (ou quoi que ce soit qui accomplit cet effet en particulier de la mise en œuvre) sont garantis d'être mutuellement exclusifs, le tampon peut être partagée par les différents threads. Cela va rapidement conduire à la corruption de l'état interne du flux.

Et même si l'accès à la mémoire tampon est garanti d'être thread-safe, que pensez-vous qui va se passer dans ce code?

// in one thread
cout << "The operation took " << result << " seconds.";

// in another thread
cout << "Hello world! Hello " << name << "!";

Vous voulez probablement chaque ligne ici à la loi de l'exclusion mutuelle. Mais comment une mise en œuvre de la garantie que?

En C++11, nous avons des garanties. Le FDIS dit ce qui suit dans le §27.4.1 [iostream.objets.aperçu]:

L'accès simultané à un synchronisée (§27.5.3.4) standard iostream de l'objet formatés et non formatés d'entrée (§27.7.2.1) et de sortie (§27.7.3.1) des fonctions ou à une norme C flux par plusieurs threads ne doit pas entraîner dans les données de la course (§1.10). [ Remarque: les Utilisateurs doivent toujours synchroniser l'utilisation simultanée de ces objets et des cours d'eau en plusieurs threads s'ils veulent éviter entrelacés caractères. - la note de fin ]

Donc, vous n'obtiendrez pas corrompu cours d'eau, mais vous avez encore besoin de les synchroniser manuellement si vous ne voulez pas que la sortie de la poubelle.

15voto

Nemo Points 32838

C'est une grande question.

Tout d'abord, C++98/C++03 a pas la notion de "thread". Donc, dans ce monde, la question est dénuée de sens.

Qu'en C++0x? Voir Martinho de la réponse (qui je l'avoue m'a surpris).

Comment sur des implémentations spécifiques de pré-C++0x? Ainsi, pour exemple, voici le code source pour basic_streambuf<...>:sputc de GCC 4.5.2 ("streambuf" header):

 int_type
 sputc(char_type __c)
 {
   int_type __ret;
   if (__builtin_expect(this->pptr() < this->epptr(), true)) {
       *this->pptr() = __c;
        this->pbump(1);
        __ret = traits_type::to_int_type(__c);
      }
    else
        __ret = this->overflow(traits_type::to_int_type(__c));
    return __ret;
 }

Clairement, ce n'effectue aucun verrouillage. Et n' xsputn. Et c'est certainement le type de streambuf que le cout utilise.

Aussi loin que je peux dire, libstdc++ effectue pas de verrouillage autour de l'un quelconque des flux d'opérations. Et je ne voudrais pas que tout, que serait lente.

Donc, avec cette mise en œuvre, évidemment, il est possible pour les deux fils de sortie de corrompre les uns des autres (pas seulement interleave).

Ce code pourrait-il endommager la structure de données elle-même? La réponse dépend des interactions possibles de ces fonctions; par exemple, ce qui se passe si un thread essaie de vider la mémoire tampon pendant que l'autre essaie de l'appeler xsputn ou quoi que ce soit. Il peut dépendre de la façon dont votre compilateur et le CPU décider de réorganiser la mémoire des charges et les magasins; il faudrait une analyse minutieuse pour être sûr. Il dépend aussi de ce que votre CPU ne si deux threads tentent de modifier le même endroit en même temps.

En d'autres termes, même si elle arrive à fonctionner correctement dans votre environnement actuel, il pourrait casser lorsque vous mettez à jour votre runtime, compilateur, ou CPU.

Résumé: "je ne le ferais pas". Construire une classe de log qui n'bon verrouillage, ou de passer à C++0x.

Comme une faiblesse de l'alternative, vous pouvez définir le cout pour sans tampon. Il est probable (mais pas garanti) qui serait ignorer que la logique liée à la mémoire tampon et appelez - write directement. C'est peut-être trop lent.

7voto

phoxis Points 14005

La Norme C++ ne précise pas si l'écriture de flux est thread-safe, mais généralement, il n'.

http://www.techrepublic.com/article/use-stl-streams-for-easy-c-thread-safe-logging/5072104

et aussi: Sont des flux de sortie standard en C++ thread-safe (cout, eree, boucher)?

Mise à JOUR

Jetez un oeil à @Martinho Fernandes réponse, de savoir ce que la nouvelle norme C++11 raconte cette.

6voto

Michael Burr Points 181287

Comme d'autres réponses mentionner, ce n'est certainement spécifique au fournisseur depuis la norme C++ ne fait aucune mention de filetage (cela change dans C++0x).

GCC n'est pas de faire un tas de promesses au sujet de la sécurité des threads et I/O. Mais la documentation de ce qu'il fait la promesse est ici:

la clé de choses est probablement:

L' __base_type de fichier est tout simplement un collection de petits wrappers autour de le C stdio couche (de nouveau, voir le lien en vertu de la Structure). Nous n'avons pas de verrouillage nous-mêmes, mais il suffit de passer à les appels à fopen, fwrite, et ainsi de suite.

Donc, pour la 3.0, la question de "est le multithreading sûr pour les I/O" doit être répondu, "est votre plate-forme de C bibliothèque de threads pour les I/O?" Certains sont par défaut, certains ne le sont pas; beaucoup offrent des plusieurs implémentations de la C bibliothèque avec différents compromis de threadsafety et de l'efficacité. Vous, les programmeur, sont toujours nécessaires pour prendre soin avec plusieurs threads.

(À titre d'exemple, la norme POSIX exige que C stdio FICHIER* opérations sont atomiques. POSIX conforme C bibliothèques (e.g, Solaris et GNU/Linux) ont un mutex pour sérialiser les opérations sur le FICHIER*. s. Cependant, vous avez encore besoin de ne pas le faire des choses stupides comme l'appel de la fonction fclose(fs) dans un thread suivie par un accès de fs dans l'autre.)

Donc, si votre plate-forme de la bibliothèque C est thread-safe, alors votre fstream I/O les opérations seront des threads à l' niveau le plus bas. Pour de plus haut niveau les opérations, telles que la manipulation de la les données contenues dans le flux mise en forme des classes (par exemple, le réglage de la les rappels à l'intérieur d'un std::ofstream), vous devez vous prémunir de tels accède comme toute autre ressource partagée.

Je ne sais pas si quelque chose a changé sine le 3.0 délai mentionné.

MSVC du fil de sécurité de la documentation pour iostreams peut être trouvé ici: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx:

Un seul objet est thread-safe pour lecture à partir de plusieurs threads. Pour exemple, étant donné un objet A, c'est sûr pour lire à partir du fil 1 et de fil 2 en même temps.

Si un seul objet est en cours d'écriture par un seul thread, puis toutes les lectures et écrit pour que l'objet sur la même ou les autres threads doivent être protégés. Pour exemple, étant donné un objet A, si le thread 1 est écrit à Un, puis le thread 2 doit être empêché de lecture ou l'écriture d'A.

Il est sûr à lire et à écrire à l'un instance d'un type, même si une autre thread de lecture ou à l'écriture autre instance du même type. Par exemple, étant donné les objets A et B de le même type, c'est sûr, si A est écrit dans le thread 1 et B est lu dans le thread 2.

...

Classes iostream

Les classes iostream suivez la même règles que les autres classes, avec un exception à la règle. Il est sûr d'écrire une objet à partir de plusieurs threads. Pour exemple, le thread 1 pouvez écrire à cout à même temps que le thread 2. Cependant, cela peut résultat dans la sortie de la les deux fils étant mélangés.

Remarque: la Lecture à partir d'un flux de tampon est pas être considérée comme une opération de lecture. Elle doit être considérée comme une écriture l'opération, car cela modifie l' état de la classe.

Notez que cette information est pour la version la plus récente de MSVC (actuellement pour VS 2010/MSVC 10/cl.exe 16.x). Vous pouvez sélectionner les informations pour les anciennes versions de MSVC à l'aide d'un menu déroulant sur la page (et de l'information est différente pour les anciennes versions).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X