2

ここでスレッドセーフなコードを実行しています。一度に 1 つのスレッドのみで実行する必要があるコードのセクションを保護するためにミューテックスを使用しています。私が抱えている問題は、このコードを使用すると、2 つの Mutex オブジェクトが作成されることがあります。ちなみに静的関数です。ミューテックス オブジェクトが 1 つだけ作成されるようにするにはどうすればよいですか??

/*static*/ MyClass::GetResource()
{

if (m_mutex == 0)
{
// make a new mutex object
m_mutex = new MyMutex();
}

m_mutex->Lock();
4

5 に答える 5

12

m_mutex呼び出す前に外部で作成するだけGetResource(),です。これにより、ミューテックスの実際の作成に関するクリティカルセクションが削除されます。

MyClass::Init()
{
  m_mutex = new Mutex;
}    

MyClass::GetResource()
{
  m_mutex->Lock();
  ...
  m_mutex->Unlock();
}
于 2009-08-27T01:30:46.577 に答える
8

問題は、m_mutex が 0 であるかどうかを確認した後にスレッドが中断される可能性がありますが、mutex を作成する前ではなく、別のスレッドが同じコードを実行できることです。

すぐに m_mutex に割り当てないでください。新しいミューテックスを作成し、アトミック比較交換を行います。

ターゲットプラットフォームについては言及していませんが、Windows では次のようになります。

MyClass::GetResource()
{
    if (m_mutex == 0)
    {
        // make a new mutex object
        MyMutex* mutex = new MyMutex();

        // Only set if mutex is still NULL.
        if (InterlockedCompareExchangePointer(&m_mutex, mutex, 0) != 0)
        {
           // someone else beat us to it.
           delete mutex;
        }
    }
    m_mutex->Lock();

それ以外の場合は、プラットフォームが提供する比較/交換機能に置き換えてください。

もう 1 つのオプションは、Windows Vista 以降で利用可能な1 回限りの初期化サポートを使用するか、可能であればミューテックスを事前に作成することです。

于 2009-08-27T01:27:22.260 に答える
3

遅延ミューテックスの初期化は、静的メソッドにはあまり適していません。誰も初期化に競争しないという保証が必要です。以下は、コンパイラを使用して、クラスの単一の静的ミューテックスを生成します。

/* Header (.hxx) */
class MyClass
{
    ...

  private:
    static mutable MyMutex m_mutex;  // Declares, "this mutex exists, somewhere."
};


/* Compilation Unit (.cxx) */
MyMutex MyClass::m_mutex;            // The aforementioned, "somewhere."

MyClass::GetResource()
{
    m_mutex.Lock();
    ...
    m_mutex.Unlock();
}

他のいくつかのソリューションでは、仲間のプログラマーの追加の仮定が必要になります。たとえば、「call init()」メソッドでは、初期化メソッドが呼び出されたことを確認する必要があり、全員がこのルールを知っている必要があります。

于 2009-08-27T01:45:59.793 に答える
2

とにかくポインタを使うのはなぜですか?ポインタを動的メモリ管理を必要としない実際のインスタンスに置き換えてみませんか?これにより、競合状態が回避され、関数へのすべての呼び出しにパフォーマンスヒットが課されることはありません。

于 2009-08-27T01:35:28.040 に答える
0

コードの特定の 1 つのセクションを保護するだけなので、関数内で静的に宣言するだけです。

static MyClass::GetResource()
{
    static MyMutex mutex;

    mutex.Lock();
    // ...
    mutex.Unlock();

変数は、静的ストレージ期間を持つローカル変数です。これは、標準で明示的に述べられています。

実装は、実装が名前空間スコープ (3.6.2) で静的またはスレッド ストレージ期間を持つ変数を静的に初期化することを許可されているのと同じ条件下で、静的またはスレッド ストレージ期間を持つ他のブロック スコープ変数の早期初期化を実行することが許可されます。それ以外の場合、そのような変数は、コントロールがその宣言を最初に通過するときに初期化されます。そのような変数は、初期化の完了時に初期化されたと見なされます。例外をスローして初期化が終了した場合、初期化は完了していないため、次に制御が宣言に入ったときに再試行されます。変数の初期化中に制御が同時に宣言に入った場合、同時実行は初期化の完了を待ちます。

最後の文はあなたにとって特に興味深いものです。

于 2014-02-20T12:09:35.920 に答える