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++免费学习笔记(深入)”;

ARTi.PiCS
ARTi.PiCS

ARTi.PiCS是一款由AI驱动的虚拟头像生产器,可以生成200多个不同风格的酷炫虚拟头像

下载
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,也要自己同步)

相关专题

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

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

479

2023.08.10

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

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

143

2025.12.24

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

78

2026.01.09

c++框架学习教程汇总
c++框架学习教程汇总

本专题整合了c++框架学习教程汇总,阅读专题下面的文章了解更多详细内容。

46

2026.01.09

学python好用的网站推荐
学python好用的网站推荐

本专题整合了python学习教程汇总,阅读专题下面的文章了解更多详细内容。

121

2026.01.09

学python网站汇总
学python网站汇总

本专题整合了学python网站汇总,阅读专题下面的文章了解更多详细内容。

12

2026.01.09

python学习网站
python学习网站

本专题整合了python学习相关推荐汇总,阅读专题下面的文章了解更多详细内容。

15

2026.01.09

俄罗斯手机浏览器地址汇总
俄罗斯手机浏览器地址汇总

汇总俄罗斯Yandex手机浏览器官方网址入口,涵盖国际版与俄语版,适配移动端访问,一键直达搜索、地图、新闻等核心服务。

71

2026.01.09

漫蛙稳定版地址大全
漫蛙稳定版地址大全

漫蛙稳定版地址大全汇总最新可用入口,包含漫蛙manwa漫画防走失官网链接,确保用户随时畅读海量正版漫画资源,建议收藏备用,避免因域名变动无法访问。

370

2026.01.09

热门下载

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

精品课程

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

共94课时 | 6.5万人学习

C 教程
C 教程

共75课时 | 4万人学习

C++教程
C++教程

共115课时 | 11.9万人学习

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

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