C++標準ライブラリのI/Oストリームが提供するstd::cout
に対して、複数スレッドから同時に出力したときの振る舞いについてメモ。(C++03以前については、処理系依存が自明のため対象としない。)
C++11標準規格によれば、下記が保証される。
- 既定の状態 または
std::sync_with_stdio(true);
を呼び出したのち、 cout
に対する出力操作*1を、複数スレッドから並行に行ってもデータ競合(data race)を引き起こさない。
#include <iostream> #include <future> void dump(const char* s, int v) { std::cout << s << "=" << v << std::endl; // 複数スレッドで並行実行されても安全(※) } int main() { auto handle = std::async(std::launch::async, dump, "xyz", 42); // 別スレッド上でdump("xyz", 42);を呼び出す dump("abc", 0); handle.wait(); // async()で作成された別スレッドの完了待ち return 0; }
※ ただし「並行アクセスをしてもcout
オブジェクトが壊れない」「指定したデータが標準出力に出力される」ことが保証されるだけであり、標準出力へ実際に出力される順序は不定。上記コードの出力結果の一例としてはxyz=abc=0\n42\n
などが起こりえる。*2
結局のところ、プログラマが意図した書式で出力させるにはmutexなどの同期機構が別途必要。
#include <mutex> std::mutex cout_guard; void dump(const char* s, int v) { std::lock_guard<std::mutex> lk(cout_guard); // 1行出力する処理を保護 std::cout << s << "=" << v << std::endl; } // 標準出力には xyz=42\nabc=0\n または abc=0\nxyz=42\n のいずれかが出力される。
N3337 27.4.1/p4, 27.5.3.4/p1-2より引用。
4 Concurrent access to a synchronized (27.5.3.4) standard iostream object’s formatted and unformatted input (27.7.2.1) and output (27.7.3.1) functions or a standard C stream by multiple threads shall not result in a data race (1.10). [Note: Users must still synchronize concurrent use of these objects and streams by multiple threads if they wish to avoid interleaved characters. -- end note]
bool sync_with_stdio(bool sync = true);
1 Returns:true
if the previous state of the standard iostream objects (27.4) was synchronized and otherwise returnsfalse
. The first time it is called, the function returnstrue
.
2 Effects: If any input or output operation has occurred using the standard streams prior to the call, the effect is implementation-defined. Otherwise, called with a false argument, it allows the standard streams to operate independently of the standard C streams.
関連URL