## 23.2 ロックメカニズム

ロックメカニズムは、再入可能ロックなしで最大の効率が得られるように考えられています。このスキーマには、2 種類の相互排他オブジェクトがあります。

- 最初の相互排他オブジェクトは、クラス ios_base にあります。このクラスでは、ストリームに実行されるすべての書式設定演算、ストリームに対する新しいロケールオブジェクトの組み込み、生の記憶装置のメカニズムのアクセス (pword, iword) に、マルチスレッド安全を設定します。これらの演算を実行する関数では、あらかじめ相互排他オブジェクトをロックし、演算の終了後にロックを解除します。これらの演算は時間的な制約が少なく、また、文字の挿入といったバッファ演算に比べると発生頻度も高くありません。この相互排他オブジェクトは、 ios_base か basic_ios にあります。
- 2 番目の相互排他オブジェクトは、basic_streambuf クラスにあり、バッファを保護します。バッファの演算はパフォーマンスに直接関係するため、この相互排他オブジェクトのロックおよびロック解除機能は重要です。

独立したバッファ演算のたびに、バッファのロックとロックの解除を繰り返すのは非効率的です。たとえば、文字の `char*` シーケンスを挿入する場合、文字を挿入するたびにインライン basic_streambuf 関数に対する呼び出しが行われます。したがって、ロックメカニズムも高いレベルで実行されます。書式付きストリーム関数と、書式なしストリーム関数のいずれについても、監視オブジェクトコンストラクタに対してロックが設定され、監視オブジェクトデストラクタに対してロックが解除されます。関数で監視クラスを使用しない場合、ロックは関数内部に直接設定されます。basic_istream::seekg と basic_ostream::seekg の場合がそうです。

次に例を挙げます。

スレッド 1: |  | スレッド 2:
`cout << "Hello Thread 1" << endl;` |  | `cout << "Hello Thread 2" << endl;`

スレッド 1 でバッファを最初にロックすると、文字シーケンス `"Hello Thread 1"` は `stdout` に出力され、ロックが解除されます。スレッド 2 がロックを引き継ぎ、文字シーケンスを出力して解除します。

### 23.2.1 バッファの保護

basic_streambuf 相互排他オブジェクトでは、ストリームの演算ごとにロックが 1 回設定されます。このスキーマは、高いパフォーマンスが得られるという点で明らかに有利ですが、バッファの機能を直接利用している間は、バッファが保護されません。これを解決するために、関数とマニピュレータが用意されています。次の例で、この機能を説明します。

スレッド 1: |  | スレッド 2:
`cout << "Hello Thread 1" << endl;` |  | `cout<< __lock;` do { cout.rdbuf()->sputc(*t); } while ( *t++!=0 ) cout << __unlock;

このスキーマでは、スレッド 2 を最初に実行すると、文 `cout<< __lock;` を呼び出すときに、`cout.rdbuf()` によって示されている basic_streambuf オブジェクトがロックされます。スレッド 1 では、ロックを解除する文 `cout << __unlock;` にスレッド 2 が達するまで、文字シーケンスを出力することはできません。この方法は、利用しやすく、ストリームとバッファの両方の操作で高いパフォーマンスが得られます。

### 23.2.2 複数のストリーム操作のロック

1 つのスレッドにある複数のスレッドをロックして、同時に実行する複数のスレッドによって実行される操作の大域上の順序を守ることができます。次の例は、この方法を示したものです。

スレッド 1: |  | スレッド 2:
`cout << __lock;` `cout << "Thread 1 begin" << endl;` `cout << "Thread 1 completion" << endl;` `cout << __unlock;` |  | `cout << "Thread 2 begin" << endl;`

この例では、cout に結合している basic_streambuf オブジェクトをスレッド 1 で最初にロックすると、スレッド 1 が文 cout << __unlock`;` に達するまで、スレッド 2 では文字シーケンスを出力することができません。その結果、次のように出力順序が守られます。

スレッド 1 が最初にロックされる: |  | `スレッド 1 開始` `スレッド 1 終了` `スレッド 2 開始`
スレッド 2 が最初にロックされる: |  | `スレッド 2 開始` `スレッド 1 開始` `スレッド 1 終了`

Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。

OEM リリース, 1998 年 6 月