螺纹安全和管道到流
Thread safety and piping to streams
如果两个不同的线程分别尝试将一段数据写入输出流,是否可以保证此操作对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
和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;
}
[iostreams.threadsafety]/1除非另有说明,否则多个线程对流对象 (30.8, 30.9(、流缓冲区对象 (30.6( 或 C 库流 (30.11( 的并发访问可能会导致数据争用 (4.7(。[注意:数据争用会导致未定义的行为 (4.7(。—尾注]
[iostream.objects.overview]/5多个线程并发访问同步 (30.5.3.4( 标准 iostream 对象的格式化和未格式化输入 (30.7.4.1( 和输出 (30.7.5.1( 函数或标准 C 流不会导致数据争用 (4.7(。[注意:如果用户希望避免交错字符,他们仍必须同步多个线程对这些对象和流的并发使用。—尾注]
这里的"标准iostream对象"是std::cin
、std::cout
、std::cerr
、std::clog
和相应的宽流之一(wcin
等(。除非以前在其上调用过sync_with_stdio(false)
否则此类流是同步的。
因此,对std::cout
等人的并发写入不会导致数据争用,但允许交错字符。对任何其他流(例如字符串流、文件流(的并发写入通过数据争用表现出未定义的行为。
- 从不同线程使用int64的不同字节安全吗
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在进程中对同一管道进行读取和写入时C++管道出现问题
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- IPC使用多个管道和分支进程来运行Python程序
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 通过网络、跨平台传递std::变体是否安全
- 在std::thread中,joinable()然后join()线程安全吗
- 使用std::istream::peek()总是安全的吗
- 从值小于256的uint16到uint8的Endian安全转换
- 在c++队列中使用pop和visit实现线程安全
- 在类型和包装器之间reinterpret_cast是否安全<Type>?
- 以线程安全的方式调用"QQuickPaintedItem::updateImage(const QImage&image)"(no QThread)
- 如何创建函数管道,以便函数一个接一个地运行?
- 螺纹安全管道端接
- 螺纹安全和管道到流
- 在不同平台上通过管道传输数据的最佳和安全方式
- 从安全角度来看,在 Windows 中使用管道是否被认为是危险的