C++11及以后标准流的线程安全性与写入原子性问询
C++11+ 标准输出流的线程安全性详解
针对你提出的问题,我来逐个梳理各类流的线程安全特性:
核心结论
在C++11及后续标准中,不同线程通过单次<<运算符调用写入同一流的行为,线程安全性因流类型而异:
- std::stringstream:无线程安全保证。这类非同步的内存流,标准未规定并发访问的同步机制。多个线程同时操作同一个
stringstream实例,可能导致流内部状态损坏、数据交错,属于未定义行为。 - std::cout / std::cerr:标准明确保证单次
<<调用是原子操作。也就是说,每个线程通过一次<<写入的"一段数据"(比如单个字符、一个字符串)不会与其他线程的单次写入内容交错,也不会导致流损坏。但要注意:如果是多次<<拼接(例如cout << "hello" << "world"),这本质是多个独立的<<调用,标准不保证这整个序列的原子性,可能被其他线程打断。 - std::fstream:无线程安全保证。和
stringstream一样,标准未对文件流的并发访问做同步要求,并发写入同一个fstream对象会触发未定义行为,可能出现数据乱序、文件损坏等问题。
测试验证情况
我在Ubuntu 18.04环境下,使用gcc 7.3.0编译器,以-std=c++17 -pthread -O3参数编译运行了测试代码,未观察到数据交错的情况。
测试代码
#include <iostream> #include <thread> #include <string> // 向流中写入count个重复字符c,每次写入调用一次<< void write_repeated_chars(char c, int count) { for (int i = 0; i < count; ++i) { std::cout << c; } } int main() { const int million = 1000000; // 创建两个线程,分别写入百万个0和百万个1 std::thread thread_zero(write_repeated_chars, '0', million); std::thread thread_one(write_repeated_chars, '1', million); thread_zero.join(); thread_one.join(); std::cout << '\n'; return 0; }
测试结果
运行后输出为连续的百万个0接着百万个1,或者反过来(取决于线程调度顺序),但从未出现0和1交错的情况,这完全符合C++标准对std::cout单次<<调用原子性的保证。
内容的提问来源于stack exchange,提问作者Antonio Perez
相关产品推荐
相关产品推荐

