Oracle® Solaris Studio 12.4: C++ ユーザーズガイド

印刷ビューの終了

更新: 2014 年 12 月
 
 

10.3 C++ 標準ライブラリのオブジェクトのスレッド間での共有

C++ 標準ライブラリ (libCstd -library=Cstd) は一部のロケールを除き、マルチスレッドに対して安全です。これは、ライブラリの内部がマルチスレッド環境で適切に動作することを保証します。ただし、スレッド間で共有するライブラリオブジェクトには、ロックを配置する必要があります。setlocale(3C) および attributes(5) のマニュアルページを参照してください。

たとえば、文字列をインスタンス化し、この文字列を新しく生成したスレッドに参照で渡した場合は、この文字列への書き込みアクセスにロックを追加する必要があります。これは、同じ文字列オブジェクトを、プログラムが複数のスレッドで明示的に共有しているからです。この処理を行うために用意されたライブラリの機能については後述します。

一方、文字列を新しいスレッドに値で渡す場合は、ライブラリが参照カウントされた実装を使用していても、ロックについて心配する必要はありません。このような場合のロックは、ライブラリが自動的に処理します。プログラム自身でロックを行う必要があるのは、スレッド間での参照渡しや、大域オブジェクトや静的オブジェクトを使用して、同じオブジェクトを複数のスレッドから明示的に使用できるようにした場合だけです。

複数のスレッドが存在する場合の動作を保証するために、C++ 標準ライブラリの内部で使用されるロック (同期) メカニズムは、次のように説明することができます。

マルチスレッドでの安全性を実現する機能は、2 つの同期クラス、_RWSTDMutex_RWSTDGuard によって提供されます。

_RWSTDMutex クラスは、プラットフォームに依存しないロック機能を提供します。このクラスには、次のメンバー関数があります。

  • void acquire()– 自分自身に対するロックを獲得する。または、このロックを獲得できるまでブロックする。

  • void release()– 自分自身に対するロックを解除する。

class _RWSTDMutex
{
public:
    _RWSTDMutex ();
    ~_RWSTDMutex ();
    void acquire ();
    void release ();
};

_RWSTDGuard クラスは、_RWSTDMutex クラスのオブジェクトをカプセル化するための便利なラッパークラスです。_RWSTDGuard クラスのオブジェクトは、自分自身のコンストラクタの中で、カプセル化された相互排他ロック (mutex) を獲得しようとします。エラーが発生した場合は、このコンストラクタは std::exception から派生している ::thread_error 型の例外を送出します。獲得された相互排他ロックは、このオブジェクトのデストラクタの中で解除されます。このデストラクタは例外を送出しません。

class _RWSTDGuard
{
public:
    _RWSTDGuard (_RWSTDMutex&);
    ~_RWSTDGuard ();
};

さらに、_RWSTD_MT_GUARD(mutex) マクロ (従来の _STDGUARD) を使用すると、マルチスレッドの構築時にだけ _RWSTDGuard クラスのオブジェクトを生成できます。生成されたオブジェクトは、そのオブジェクトが定義されたコードブロックの残りの部分が、複数のスレッドで同時に実行されないようにします。単一スレッドの構築時には、マクロが空白の式に展開されます。

これらの機能は、次のように使用します。

#include <rw/stdmutex.h>

//
// An integer shared among multiple threads.
//
int I;

//
// A mutex used to synchronize updates to I.
//
_RWSTDMutex I_mutex;

//
// Increment I by one. Uses an _RWSTDMutex directly.
//

void increment_I ()
{
   I_mutex.acquire(); // Lock the mutex.
   I++;
   I_mutex.release(); // Unlock the mutex.
}

//
// Decrement I by one. Uses an _RWSTDGuard.
//

void decrement_I ()
{
   _RWSTDGuard guard(I_mutex); // Acquire the lock on I_mutex.
   --I;
   //
   // The lock on I is released when destructor is called on guard.
   //
}