0

0

c++20的std::osyncstream如何保证多线程输出不交错? (同步流)

裘德小鎮的故事

裘德小鎮的故事

发布时间:2026-01-11 11:35:55

|

943人浏览过

|

来源于php中文网

原创

std::osyncstream 不保证线程安全,仅提供缓冲区独占与析构时原子刷出;若多个 osyncstream 绑定同一 ostream(如 cout)且无额外同步,输出仍会交错。

c++20的std::osyncstream如何保证多线程输出不交错? (同步流)

std::osyncstream 本身不保证线程安全,它只提供「缓冲区独占 + 自动刷出」机制;真正防止输出交错,靠的是构造时传入的 std::basic_osyncstream 底层绑定的 std::ostream& 是否被其他线程同时写入 —— 如果多个 std::osyncstream 同时绑定到同一个 std::cout,且未加锁,依然会交错。

为什么 std::osyncstream 构造后立即刷出?

它在析构时调用 emit(),把本地缓冲区内容原子地写入绑定的 ostream(如 std::cout)。这个“原子写入”不是指线程安全,而是指:一次 emit() 调用对底层流的写操作是完整、不可分割的 —— 但前提是,没有别的线程正直接写这个流。

  • 构造 std::osyncstream 会分配独立缓冲区,隔离当前线程的格式化输出
  • 所有 std::cout
  • 离开作用域时自动调用 emit(),将整块缓冲内容以单次 rdbuf()->sputn() 写入目标流
  • 如果目标流(如 std::cout)本身被其他线程直接调用 operator,emit() 和那个直接写入就可能交错

std::osyncstream 必须搭配 std::cout 的线程同步使用

单独用 std::osyncstream 无法解决竞争,必须确保:同一时间,只有一个线程在向底层 std::ostream 执行写操作(无论是通过 std::osyncstream::emit() 还是直接

  • 推荐方式:所有线程统一通过 std::osyncstreamstd::cout,且不混用裸 std::cout
  • 不推荐方式:部分线程用 std::osyncstream,部分用 std::cout —— 交错必然发生
  • 更稳妥方式:配合 std::mutex 锁住 std::cout,再用 std::osyncstream(冗余但安全)
  • std::osyncstream 不拥有流,也不管理流的生命周期;绑定后不能移动/复制,仅限栈上短生命周期使用

一个典型安全用法示例

下面代码中,每个线程都只通过 std::osyncstream 输出,且不直接碰 std::cout

立即学习C++免费学习笔记(深入)”;

千面数字人
千面数字人

千面 Avatar 系列:音频转换让静图随声动起来,动作模仿让动漫复刻真人动作,操作简单,满足多元创意需求。

下载
void worker(int id) {
    std::osyncstream os{std::cout}; // 绑定到 std::cout
    os << "Thread " << id << " starts\n";
    os << "Thread " << id << " finishes\n";
    // 离开作用域,自动 emit(),整行写入 cout
}

int main() {
    std::vector threads;
    for (int i = 0; i < 3; ++i) {
        threads.emplace_back(worker, i);
    }
    for (auto& t : threads) t.join();
}

输出不会出现 “Thread 1 start\nThread 2 st” 这类字符级交错,但依然可能出现两行顺序颠倒(如 T2 先 finish、T1 后 start),因为不同线程的 emit() 调用仍受调度影响 —— std::osyncstream 只保单次 emit 原子,不保多线程 emit 的全局顺序。

容易忽略的关键点

很多人以为 std::osyncstream 是“线程安全的 cout”,其实它只是个带自动刷出的同步包装器。真正易错的地方在于:

  • 误以为绑定后 std::cout 就自动线程安全了 —— 它没有加锁,也没拦截裸调用
  • 在 lambda 或异步任务里捕获 std::osyncstream 并延长其生命周期,导致绑定流被提前析构
  • 跨 DLL 边界传递 std::osyncstream(ABI 不稳定,C++20 实现尚未完全统一)
  • std::ofstream 使用 std::osyncstream 时,忘了文件流本身不支持多线程并发写(即使加 syncstream,也要自己同步)

相关专题

更多
线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

482

2023.08.10

Python 多线程与异步编程实战
Python 多线程与异步编程实战

本专题系统讲解 Python 多线程与异步编程的核心概念与实战技巧,包括 threading 模块基础、线程同步机制、GIL 原理、asyncio 异步任务管理、协程与事件循环、任务调度与异常处理。通过实战示例,帮助学习者掌握 如何构建高性能、多任务并发的 Python 应用。

143

2025.12.24

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

5

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

6

2026.01.21

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

11

2026.01.21

C++多线程相关合集
C++多线程相关合集

本专题整合了C++多线程相关教程,阅读专题下面的的文章了解更多详细内容。

4

2026.01.21

无人机驾驶证报考 uom民用无人机综合管理平台官网
无人机驾驶证报考 uom民用无人机综合管理平台官网

无人机驾驶证(CAAC执照)报考需年满16周岁,初中以上学历,身体健康(矫正视力1.0以上,无严重疾病),且无犯罪记录。个人需通过民航局授权的训练机构报名,经理论(法规、原理)、模拟飞行、实操(GPS/姿态模式)及地面站训练后考试合格,通常15-25天拿证。

16

2026.01.21

Python多线程合集
Python多线程合集

本专题整合了Python多线程相关教程,阅读专题下面的文章了解更多详细内容。

1

2026.01.21

java多线程相关教程合集
java多线程相关教程合集

本专题整合了java多线程相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 7.2万人学习

C 教程
C 教程

共75课时 | 4.1万人学习

C++教程
C++教程

共115课时 | 13.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号