C++ ライブラリ・リファレンス

オブジェクトのロック

共有オブジェクトとマルチスレッドで起こる問題の最も簡単な解決方法は、iostream オブジェクトを 1 つのスレッドに対して局所的にして問題自体をなくしてしまうことです。そのためには、次のような方法があります。

ところが多くの場合 (たとえばデフォルトの共有標準ストリームオブジェクトの場 合)、オブジェクトを特定のスレッドの局所オブジェクトとすることが不可能で、他の解決策を探さなければなりません。

iostream クラスのオブジェクトに対する一連の操作を不可分命令的に実行するには、なんらかのロックを使用する必要があります。ロックを行うと、シングルスレッド用のアプリケーションの場合でもいくらかオーバーヘッドが起こります。ロックを使用するか、あるいは、iostream オブジェクトをスレッドの非公開オブジェクトとするかは、アプリケーションで採用しているスレッドモデルによります。

各スレッドが独立の場合と、複数スレッドが共同作業を行う場合

stream_locker クラス

iostream ライブラリでは、iostream オブジェクトに対する一連の操作をロックするための stream_locker クラスが提供されています。したがって、iostream のロックとロック解除を動的に設定することによるオーバーヘッドを最小にすることができます。

stream_locker クラスのオブジェクトを使用すると、ストリームオブジェクトに対する一連の操作を不可分命令的に実行することができます。たとえば、次の例では、ファイル内の位置を指定して、そこからデータを 1 ブロック読み込みます。


例 4-10 ロック操作を使用する例

#include <fstream.h>
#include <rlocks.h>
void lock_example (fstream& fs)
{
    const int len = 128;
    char buf[len];
    int offset = 48;
        stream_locker s_lock(fs, stream_locker::lock_now);
        . . . . .// ファイルをオープン
        fs.seekg(offset, ios::beg);
        fs.read(buf, len);
}

この例では、stream_locker オブジェクトのコンストラクタが相互排他制御域の開始を定義します。相互排他制御域では、一度に 1 つのスレッドしか実行されません。また、関数から戻った後で呼び出されるデストラクタでは、相互排他制御域の終了を定義します。したがって、stream_locker オブジェクトにより、ファイル内の特定の位置のシークと、ファイルからのデータの読み込みとが不可分命令的に実行されます。スレッド A がファイルからデータを読み込む前に、スレッド B がファイル内の位置を変えてしまうことができなくなるためです。

stream_locker オブジェクトのもう 1 つの使用方法として、相互排他制御域を明示的に定義する方法があります。次の例では、入出力操作とそれに続くエラー検査を不可分命令的に実行するため、stream_locker オブジェクトのメンバー関数 lock と unlock を呼び出します。


例 4-11 入出力操作とエラー検査を不可分命令的に実行

{
     ...
     stream_locker file_lck(openfile_stream,
                               stream_locker::lock_defer);
     ....
     file_lck.lock();  // openfile_stream をロック
     openfile_stream << "Value: " << int_value << "¥n";
     if(!openfile_stream) {
             file_error("Output of value failed¥n");
             return;
     }
     file_lck.unlock();  // openfile_stream のロックを解除
}

stream_locker についての詳細は、stream_locker(3) のマニュアルページを参照してください。