En général, je suppose que les flux ne sont pas synchronisés, c'est à l'utilisateur de faire le verrouillage approprié. Cependant, des choses comme cout
obtenir un traitement spécial dans la bibliothèque standard?
Autrement dit, si plusieurs threads écrivent, cout
peuvent-ils corrompre l' cout
objet? Je comprends que même si synchronisé, vous obtiendrez toujours une sortie entrelacée de manière aléatoire, mais cet entrelacement est-il garanti? Autrement dit, est-il sûr de l'utiliser à cout
partir de plusieurs threads?
Ce fournisseur dépend-il? Que fait 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 ne concerne pas non plus les appels système sous-jacents, ce sont bien, mais les flux ajoutent une couche de tampon par-dessus.
printf
brille car la sortie complète est écritestdout
en un seul coup; lors de l'utilisation destd::cout
chaque maillon de la chaîne d'expression, il serait émis séparément versstdout
; entre eux, il peut y avoir un autre thread d'écriture àstdout
cause duquel l'ordre de la sortie finale est perturbé.Réponses:
Le standard C ++ 03 n'en dit rien. Lorsque vous n'avez aucune garantie sur la sécurité des threads de quelque chose, vous devez le traiter comme non thread-safe.
Le fait qu'il
cout
soit tamponné est particulièrement intéressant ici . Même si les appels àwrite
(ou quoi que ce soit qui accomplit cet effet dans cette implémentation particulière) sont garantis d'être mutuellement exclusifs, le tampon peut être partagé par les différents threads. Cela conduira rapidement à une corruption de l'état interne du flux.Et même si l'accès au tampon est garanti pour les threads, que pensez-vous qu'il va se passer dans ce code?
Vous voulez probablement que chaque ligne ici agisse dans l'exclusion mutuelle. Mais comment une implémentation peut-elle garantir cela?
En C ++ 11, nous avons certaines garanties. Le FDIS dit ce qui suit au §27.4.1 [iostream.objects.overview]:
Ainsi, vous n'obtiendrez pas de flux corrompus, mais vous devez toujours les synchroniser manuellement si vous ne voulez pas que la sortie soit des déchets.
la source
cout.sync_with_stdio()
c'est vrai, utilisercout
pour sortir des caractères de plusieurs threads sans synchronisation supplémentaire est bien défini, mais uniquement au niveau des octets individuels. Ainsi,cout << "ab";
etcout << "cd"
exécuté dans différents threads peut généreracdb
, par exemple, mais ne peut pas provoquer un comportement indéfini.c'est une excellente question.
Premièrement, C ++ 98 / C ++ 03 n'a pas de concept de "thread". Donc, dans ce monde, la question n'a pas de sens.
Qu'en est-il de C ++ 0x? Voir la réponse de Martinho (qui, je l'avoue, m'a surpris).
Qu'en est-il des implémentations spécifiques pré-C ++ 0x? Eh bien, par exemple, voici le code source
basic_streambuf<...>:sputc
de GCC 4.5.2 (en-tête "streambuf"):De toute évidence, cela n'effectue aucun verrouillage. Et non plus
xsputn
. Et c'est certainement le type de streambuf que cout utilise.Pour autant que je sache, libstdc ++ n'effectue aucun verrouillage autour des opérations de flux. Et je ne m'attendrais à aucun, car ce serait lent.
Donc, avec cette implémentation, il est évidemment possible pour la sortie de deux threads de se corrompre ( pas seulement d'entrelacer).
Ce code pourrait-il corrompre la structure de données elle-même? La réponse dépend des interactions possibles de ces fonctions; par exemple, que se passe-t-il si un thread essaie de vider le tampon tandis qu'un autre essaie d'appeler
xsputn
ou autre. Cela peut dépendre de la manière dont votre compilateur et votre CPU décident de réorganiser les charges et les magasins de mémoire; il faudrait une analyse minutieuse pour être sûr. Cela dépend également de ce que fait votre CPU si deux threads tentent de modifier le même emplacement simultanément.En d'autres termes, même si cela fonctionne correctement dans votre environnement actuel, il peut se casser lorsque vous mettez à jour l'un de vos runtime, compilateur ou CPU.
Résumé: "Je ne le ferais pas". Créez une classe de journalisation qui effectue un verrouillage approprié ou passez à C ++ 0x.
Comme alternative faible, vous pouvez définir cout sur non tamponné. Il est probable (bien que non garanti) que toute logique liée à la mémoire tampon soit ignorée et appelée
write
directement. Bien que cela puisse être d'une lenteur prohibitive.la source
cout
.www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
et aussi: les flux de sortie standard sont-ils en C ++ thread-safe (cout, cerr, clog)?
METTRE À JOUR
Veuillez consulter la réponse de @Martinho Fernandes pour savoir ce que le nouveau standard C ++ 11 en dit.
la source
Comme d'autres réponses le mentionnent, cela est certainement spécifique au fournisseur puisque la norme C ++ ne fait aucune mention de threading (cela change dans C ++ 0x).
GCC ne fait pas beaucoup de promesses sur la sécurité des threads et les E / S. Mais la documentation de ce qu'il promet est ici:
l'essentiel est probablement:
Je ne sais pas si quelque chose a changé depuis le délai 3.0 mentionné.
La documentation de sécurité des threads de MSVC pour
iostreams
peut être trouvée ici: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :Notez que ces informations concernent la version la plus récente de MSVC (actuellement pour VS 2010 / MSVC 10 /
cl.exe
16.x). Vous pouvez sélectionner les informations des anciennes versions de MSVC à l'aide d'un contrôle déroulant sur la page (et les informations sont différentes pour les anciennes versions).la source