Если два разных потока пытаются записать один фрагмент данных каждый в выходной поток, гарантируется ли, что эта операция является поточно-ориентированной для std::string_stream
, std::cout
, std::err
и std::fstream
(в C ++ 11 и далее)? (Другими словами, есть ли гарантии, что запись в один и тот же поток из нескольких потоков не нарушит поток или не перемежает отдельные фрагменты данных?)
Под «одним фрагментом данных» я подразумеваю «с одним вызовом оператора канала <<
с использованием стандартной перегрузки библиотеки». Например, если один поток записывает строку, содержащую миллион 0
с подряд, а другой поток записывает строку, содержащую миллион 1
с подряд, есть ли гарантии, что не будет 0
с, смешанный с 1
с?
Код, проверяющий эту идею: Этот код выводит группу 1
с в одном потоке и группу 0
с в другом потоке. Я не видел чересстрочной развертки при передаче вывода в файл.
Я тестировал этот код в Ubuntu 18.04, используя gcc-7.3.0
и компилируя с флагами -std=c++17 -pthread -O3 main.cc -o main
, и я не наблюдал никакого смешивания 1
s и 0
s.
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <chrono>
auto now() {
return std::chrono::high_resolution_clock::now();
}
typedef decltype(now()) now_time_t;
int main(int argc, char** argv) {
std::stringstream A {}, B {};
int count = argc > 1 ? std::stoi(argv[1]) : 1000;
for(int i = 0; i < count; ++i) {
A << "0";
B << "1";
}
volatile bool waiting = true;
now_time_t t1_start_time, t2_start_time, t1_end_time, t2_end_time;
std::thread t1 = std::thread([&] {
while(waiting) ;
t1_start_time = now();
std::cout << A.rdbuf();
t1_end_time = now();
});
std::thread t2 = std::thread([&] {
while(waiting) ;
t2_start_time = now();
std::cout << B.rdbuf();
t2_end_time = now();
});
waiting = false;
t1.join();
t2.join();
auto t1_total_time = (t1_end_time - t1_start_time).count();
auto t2_total_time = (t2_end_time - t2_start_time).count();
std::cerr << "Time difference: " << (t1_start_time - t2_start_time).count() << std::endl;
std::cerr << "t1 total time: " << t1_total_time << std::endl;
std::cerr << "t2 total time: " << t2_total_time << std::endl;
}