10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++Advent Calendar 2020

Day 2

C++20便利機能の紹介:同期出力ストリーム std::osyncstream

Last updated at Posted at 2020-12-01

C++20標準ライブラリでは「同期出力ストリーム(synchronized output stream)」が追加されました。これによって並行実行される複数スレッドから 行単位のストリーム同時出力 を、安全かつ手軽に行えるようになります。1

C++17
#include <iostream>
#include <mutex>

// std::cout出力を保護するミューテックスを用意...
std::mutex g_cout_mutex;

// 複数スレッドからworker_thread関数が同時に呼び出されると仮定
void worker_thread(int id)
{
  {
    // 文字列"Worker#<N>"が1行で出力されることを保障するため
    // ミューテックスg_cout_mutexによる排他制御が必須!!
    std::lock_guard lk{g_cout_mutex};
    std::cout << "Worker#" << id << std::endl;
  }
  // ...
}

std::osyncstreamクラス

下記の例示ソースコードでは新ヘッダ<syncstream>をincludeし、標準出力ストリームstd::coutstd::osyncstreamでラップしています。

C++20
#include <iostream>
#include <syncstream>  // NEW

// 複数スレッドからworker_thread関数が同時に呼び出されると仮定
void worker_thread(int id)
{
  // 文字列"Worker#<N>"は他スレッド出力と混じることなく1行で出力される
  std::osyncstream{std::cout} << "Worker#" << id << std::endl;

  {
    // syncoutへのストリーム出力は一旦バッファリングされ...
    std::osyncstream syncout{std::cout};
    syncout << "Worker#" << id << " ";
    for (int n = 0; n < id; n++) {      
      syncout << (n ? "," : "[") << n;
    }
    syncout << "]" << std::endl;
  } // syncoutオブジェクト破棄時にstd::coutへアトミックに送出(emit)される
}

std::osyncstreamクラスでは、スレッド間の排他制御は「ラップ対象の出力ストリーム(先例ではstd::cout)」に対して行われます。つまりストリーム出力操作(operetor<<)を行う std::osyncstreamオブジェクト自体は異なっていてもよく、実際にストリーム出力を行う箇所で一時オブジェクトの生成/破棄を行えば十分です。

合わせて関連するマニピューレータ(emit_on_flush,noemit_on_flush,flush_emit)も追加され、より細かい制御も可能となっています。これらの機能詳細は記事「C++ Synchronized Buffered Ostream」でも紹介しています。

利用上の注意(2020/12/1現在)

2020/12/1現在、主要C++コンパイラGCC/Clang/MSVCいずれにおいても 標準ヘッダ<syncstream>は未実装 です。この便利機能を試すことはできません。どうして…

先行して試したい方向けに、提案時の参照実装を紹介しておきます。
https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/p0053_basic_osyncstreambuf

参考ページ

  1. そのままstd::cout出力すればいいんじゃね?何がダメなの?という方は記事「スレッドセーフという幻想と現実」や「C++11のcoutとスレッド安全性」をご一読ください。

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?