yohhoyの日記

技術的メモをしていきたい日記

C++ Synchronized Buffered Ostream

C++2a(C++20)に向けて(PDF)P0053R6が採択され、マルチスレッド環境下でのストリーム出力排他制御をサポートする同期化出力ストリームstd::osyncstreamが追加される。

// C++2a(C++20)
#include <syncstream>
#include <iostream>

void thread1(int value)
{
  // 下記行の処理結果がアトミックにストリーム出力される
  std::osyncstream(std::cout) << "value=" << value << '\n';
}

void thread2(int value)
{
  // 同期化出力ストリームオブジェクトを作成
  std::osyncstream syncout{std::cout};

  syncout << "value=" << value << std::endl;
  syncout.emit();  // emit呼び出しでアトミックにストリーム出力される

  syncout << "double=" << (value * 2) << std::endl;
  // osyncstreamデストラクタにより暗黙にemitが呼び出される
}

osyncstreamに対するフラッシュ操作(endlflushマニピュレータ)のみでは、実際の標準出力(std::cout)への出力が行われないことに注意。osyncstreamオブジェクトを破棄する(デストラクタ呼び出し)か、既定動作では明示的にemitメンバ関数呼び出す必要がある。

別途提案されている(PDF)P0753R1が採択されれば、同期出力ストリーム専用マニピュレータによりフラッシュ操作時の自動emitやflash+emitを明示できるようになる。
2018-04-14追記:2018年4月会合において、C++2aに向けて(PDF)P0753R2が採択された。

// P0053R6 + P0753R1
void thread3(int value)
{
  std::osyncstream syncout{std::cout};
  // フラッシュ操作+emit呼び出しを明示
  syncout << "value=" << value << '\n' << std::flush_emit;

  // フラッシュ操作で自動的にemitを呼び出すよう設定
  syncout << std::emit_on_flush; 
  // static_cast<syncbuf*>(syncout.rdbuf())->set_emit_on_sync(true);相当
  syncout << "double=" << (value * 2) << std::endl;
  syncout << "half=" << (value / 2) << std::endl;
}

関連URL