#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();
}
Biên dịch mã ở trên trong g ++ 6.2.1, sau đó chạy mã đó bằng valgrind --tool=helgrind ./a.out
. Helgrind sẽ phàn nàn:Nhà điều hành << (ostream &, obj) trên hai luồng luồng khác nhau có an toàn không?
==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"
Dường như cả hai chủ đề được gọi là locale_facet.h:widen
khiến cuộc đua dữ liệu kể từ khi có xuất hiện không đồng bộ trong hàm này, mặc dù operator <<
được kêu gọi hai đối tượng khác nhau ostringstream
. Vì vậy, tôi đã tự hỏi liệu đây có thực sự là một cuộc đua dữ liệu hay chỉ là một kết quả dương tính giả của helgrind
.
Dù tiêu chuẩn nói, * điều này nên được * threadsafe. –
Trạng thái chuẩn * Truy cập đồng thời vào đối tượng luồng (27.8, 27.9), đối tượng đệm luồng (27.6) hoặc luồng C Library (27.9.2) bằng nhiều chủ đề có thể dẫn đến cuộc đua dữ liệu (1.10) trừ khi có quy định khác (27.4). [Lưu ý: Các cuộc đua dữ liệu dẫn đến hành vi không xác định (1.10). —khi lưu ý] * Vì vậy, tôi đoán là các luồng đang sử dụng một số trạng thái toàn cục ở phần cuối không được đồng bộ hóa. Hoặc nó là dương tính giả. Ruột của tôi nói điều này nên được an toàn. – NathanOliver
Tôi nghĩ rằng điều này nên an toàn theo §17.6.5.9/2: * "Chức năng thư viện chuẩn C++ không được truy cập trực tiếp hoặc gián tiếp các đối tượng (1.10) truy cập bởi các luồng khác với luồng hiện tại trừ khi các đối tượng được truy cập trực tiếp hoặc gián tiếp qua các đối số của hàm, bao gồm 'this'." * Vì vậy, tôi muốn nói đây là một triển khai không phù hợp hoặc một kết quả dương tính giả. –