#include <iostream>
#include <sstream>
#include <thread>
using namespace std;
int main()
{
auto runner = []() {
ostringstream oss;
for (int i=0; i<100000; ++i)
oss << i;
};
thread t1(runner), t2(runner);
t1.join(); t2.join();
}
Compilez le code ci-dessus dans g ++ 6.2.1, puis exécutez-le avec valgrind --tool=helgrind ./a.out
. Helgrind se plaindraient:L'opérateur << (ostream &, obj) sur deux flux différents est-il sûr?
==5541== ----------------------------------------------------------------
==5541==
==5541== Possible data race during read of size 1 at 0x51C30B9 by thread #3
==5541== Locks held: none
==5541== at 0x4F500CB: widen (locale_facets.h:875)
==5541== by 0x4F500CB: widen (basic_ios.h:450)
==5541== by 0x4F500CB: fill (basic_ios.h:374)
==5541== by 0x4F500CB: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5541== by 0x400CD0: main::{lambda()#1}::operator()() const (43.cpp:12)
==5541== by 0x4011F7: void std::_Bind_simple<main::{lambda()#1}()>::_M_invoke<>(std::_Index_tuple<>) (functional:1391)
==5541== by 0x401194: std::_Bind_simple<main::{lambda()#1}()>::operator()() (functional:1380)
==5541== by 0x401173: std::thread::_State_impl<std::_Bind_simple<main::{lambda()#1}()> >::_M_run() (thread:197)
==5541== by 0x4EF858E: execute_native_thread_routine (thread.cc:83)
==5541== by 0x4C31A04: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5541== by 0x56E7453: start_thread (in /usr/lib/libpthread-2.24.so)
==5541== by 0x59E57DE: clone (in /usr/lib/libc-2.24.so)
==5541==
==5541== This conflicts with a previous write of size 8 by thread #2
==5541== Locks held: none
==5541== at 0x4EF3B1F: do_widen (locale_facets.h:1107)
==5541== by 0x4EF3B1F: std::ctype<char>::_M_widen_init() const (ctype.cc:94)
==5541== by 0x4F501B7: widen (locale_facets.h:876)
==5541== by 0x4F501B7: widen (basic_ios.h:450)
==5541== by 0x4F501B7: fill (basic_ios.h:374)
==5541== by 0x4F501B7: std::ostream& std::ostream::_M_insert<long>(long) (ostream.tcc:73)
==5541== by 0x400CD0: main::{lambda()#1}::operator()() const (43.cpp:12)
==5541== by 0x4011F7: void std::_Bind_simple<main::{lambda()#1}()>::_M_invoke<>(std::_Index_tuple<>) (functional:1391)
==5541== by 0x401194: std::_Bind_simple<main::{lambda()#1}()>::operator()() (functional:1380)
==5541== by 0x401173: std::thread::_State_impl<std::_Bind_simple<main::{lambda()#1}()> >::_M_run() (thread:197)
==5541== by 0x4EF858E: execute_native_thread_routine (thread.cc:83)
==5541== by 0x4C31A04: ??? (in /usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so)
==5541== Address 0x51c30b9 is 89 bytes inside data symbol "_ZN12_GLOBAL__N_17ctype_cE"
Il semble que les deux fils appelés locale_facet.h:widen
qui a causé la race de données car il n'y a pas de synchronisation apparaît dans cette fonction, même si operator <<
est appelée sur deux objets différents ostringstream
. Donc je me demandais si c'était vraiment une course de données ou juste un faux positif de helgrind
.
Quelle que soit la norme dit, ce * devrait * être threadsafe. –
Les états standard * Accès concurrentiel à un objet de flux (27.8, 27.9), objet de flux de données (27.6) ou flux de bibliothèque C (27.9.2) par plusieurs threads peuvent entraîner une course de données (1.10) sauf indication contraire (27.4). [Note: Les courses de données entraînent un comportement indéfini (1.10). -end note] * Donc, je suppose que les flux utilisent un état global dans le back-end qui n'est pas synchronisé. Ou c'est un faux positif. Mon instinct dit que cela devrait être sûr. – NathanOliver
Je pense que ceci devrait être sûr selon §17.6.5.9/2: * "Une fonction de bibliothèque standard C++ ne doit pas accéder directement ou indirectement aux objets (1.10) accessibles par des threads autres que le thread courant sauf si les objets sont directement ou indirectement les arguments de la fonction, y compris 'this'." * Donc, je dirais que c'est une implémentation non conforme ou un faux positif. –