C++20 std::osyncstream 完全指南 - 解决多线程输出混乱问题

C++中的 sync stream 是指在多线程环境下同步输出流的概念. 在 C++20 标准中实现了 std::osyncstream 相关功能, 用于解决多线程输出流竞争和混乱问题.


1. 背景: 多线程输出的混乱

在多线程环境下, 多个线程同时向 std::cout 或其他输出流写入数据时, 常会导致输出内容交错和混乱.

举一个简单的示例:

#include <iostream>
#include <thread>
#include <vector>

int main() {
  constexpr int num_thread = 10;
  std::vector<std::thread> threads;

  // 开启线程
  for (int i = 0; i < num_thread; i++) {
    threads.emplace_back(
        [](int id) { std::cout << "Thread " << id << " is doing job\n"; }, i);
  }

  // 等待线程结束
  for (auto& t : threads) {
    t.join();
  }
  return 0;
}

我们通常会希望得到如下输出(线程顺序可能不同):

Thread 0 is doing job
Thread 2 is doing job
Thread 3 is doing job
Thread 1 is doing job
Thread 4 is doing job
Thread 5 is doing job
Thread 6 is doing job
Thread 7 is doing job
Thread 8 is doing job
Thread 9 is doing job

但实际上, 输出常常是混乱的:

Thread Thread 0 is doing job
Thread 2 is doing job
1 is doing job
Thread 3 is doing job
Thread 4 is doing job
Thread 5 is doing job
Thread 6 is doing job
Thread 7 is doing job
Thread 9 is doing job
Thread 8 is doing job

这种混乱会使输出难以使用.


2. 原因解析

2.1 全局资源共享和原子操作

  1. std::cout 是全局标准输出流, 多个线程无序访问时会导致内容交错.

  2. 虽然 std::cout 保证单次操作的原子性, 例如:

    // Thread A
    std::cout << "Thread A\n";
    // Thread B
    std::cout << "Thread B\n";

    可能输出为:

    thread A
    thread B

    或者:

    thread B
    thread A

    绝不会出现内容叠加在一起的情况, 比如这种:

    thread thread A
    B

    但如果多个操作组合在一起, 例如:

    std::cout << "Thread " << id << " is doing job\n";

    输出可能会交错, 导致不可读的结果.

2.2 输出混乱的影响


3. std::osyncstream 介绍

C++20 推出了同步输出流 std::osyncstream, 用于解决上述问题.

3.1 基础原理

std::osyncstream 通过内置缓冲区, 在操作完成后一次性写入目标流, 从而保证输出内容的完整性和顺序. 每个线程有独立的缓冲区, 避免了线程间竞争.

3.2 用法示例

#include <iostream>
#include <syncstream>  // 引入对应头文件
#include <thread>
#include <vector>

int main() {
  constexpr int num_thread = 10;
  std::vector<std::thread> threads;

  // 开启线程
  for (int i = 0; i < num_thread; i++) {
    threads.emplace_back(
        [](int id) {
          std::osyncstream(std::cout) << "Thread " << id << " is doing job\n";
        },
        i);
  }

  // 等待线程结束
  for (auto& t : threads) {
    t.join();
  }
  return 0;
}

输出可以保证不会交错:

Thread 0 is doing job
Thread 3 is doing job
Thread 4 is doing job
Thread 7 is doing job
Thread 5 is doing job
Thread 1 is doing job
Thread 2 is doing job
Thread 9 is doing job
Thread 8 is doing job
Thread 6 is doing job

4. 优势和注意事项

4.1 优势

4.2 注意事项


5. 总结

std::osyncstream 是 C++20 中一个重要的新特性, 通过引入线程安全的同步输出流, 解决了多线程环境下输出混乱的问题. 其实现简单高效, 适合在多线程日志, 调试输出等场景中广泛应用. 在实际项目中, 选择合适的工具和技术, 可以显著提升系统的稳定性和可维护性.

源码链接