8

ミューテックスが関数内で定義されている場合、そのロックはその関数から呼び出される関数に適用されますか? すなわち

void f () {  
    Mutex mutex;  
    g();  
}

ロックは g() のデータ変更にも適用されますか?

また、クラス メソッドで定義されたロックは、そのクラスの特定のインスタンスにのみ適用されると言うのは正しいでしょうか? 意味:

Class Foo;  
Foo foo1, foo2;
(In thread 1) foo1.bar();  
(In thread 2) foo2.bar();  

各呼び出しは同時に発生できますか?

ミューテックスの背後にあるメカニズムを説明するリンクを誰かが説明/指摘できれば、それは素晴らしいボーナスです。ありがとう!その情報が役立つ場合、私は現在 Qt Thread ライブラリを使用しています。

4

3 に答える 3

17

あなたの例では、実際にはミューテックスをロックしないので、異なるスレッドが同時に関数にアクセスするのを妨げることはありません。また、関数内でミューテックスをローカルで宣言して、各関数呼び出しが異なるローカルミューテックスオブジェクトを使用するようにします。このミューテックスがロックされたとしても、各関数呼び出しは異なるミューテックスオブジェクトをロックし、同時アクセスを妨げません。

より良い戦略は、次のような設定です。

class A {
  QMutex mutex;

  void f() {  
    QMutexLocker ml(mutex); // Acquire a lock on mutex
    g();

    // The lock on the mutex will be released when ml is destroyed.
    // This happens at the end of this function.
  }

  // ...
};

この場合、存在するmutex限りロックされるmlため、スレッドが内部で費やしている間もロックされg()ます。f()この間に別のスレッドが呼び出されるとml、最初のスレッドが関数を離れて新しいスレッドがロックを取得できるようになるまで、オブジェクトの作成がブロックされmutexます。

于 2009-08-02T17:03:04.330 に答える
8

ミューテックスはあなたがつかむものであり、グラブしているスレッドから解放するまで、それをつかもうとする他のスレッドを停止します。

あなたの質問には、Mutex インスタンスを割り当てる関数があります。それはそれをロックするのに十分ではありません。具体的には、mutex.lock() を呼び出す必要があります (Qt でも一般的に、pthread を使用しない限り、その場合は pthread_mutex_lock を使用して、プラットフォームに依存する低レベルのものを楽しんでください。Qt はそれを非常にうまく抽象化します)。

ここにQtの例があります

  void MyClass::doStuff( int c )
    {
        mutex.lock();
        a = c;
        b = c * 2;
        mutex.unlock();
    } 

ロックを取得すると、ロックを取得したスレッドから g() の呼び出しが行われるため、コードの別の部分から他のスレッドから g() を呼び出していないと仮定すると、その呼び出しでは単独になります。ロックは、他のすべてのスレッドを停止するという意味ではありません。ロックが解放されるまで、同じロックを取得しようとするスレッドを停止します。

それがスレッドが g() に到達する唯一の方法である場合、そのアクセスで同期されます。

質問の 2 番目の部分では、ミューテックスがインスタンス属性の場合、それらは 2 つの異なるミューテックスになります。クラスミューテックスインスタンスを宣言してインスタンス化し、ロックのために参照する必要があります。その場合、クラスミューテックスをロックするクラス内のメソッドを呼び出そうとすると、効果的に同期されます。つまり、2 つのスレッドがそのメソッドを一緒に実行することはありません。

たとえば、(私は Qt を持っていないので、このコードをコンパイルできず、2 年前にコーディングを停止したため、動作しませんでした)

class Foo {
public:
   void method(void) {
      mutex.lock();
      cout << "method called";
      // long computation
      mutex.unlock();
   }

private:
  QMutex mutex;
};

この場合、1 と 2 の 2 つのスレッドと、クラス Foo の 2 つのインスタンス a と b があるとします。スレッド 1 が a.method() を呼び出し、スレッド 2 が b.method() を呼び出すとします。この場合、2 つのミューテックスは異なるインスタンスであるため、各スレッドは独立して呼び出しを実行し、並行して実行されます。

1 と 2 の 2 つのスレッドと、2 つのスレッド間で共有されるクラス Foo の 1 つのインスタンスがあるとします。スレッド 1 が a.method() を呼び出し、次にスレッド 2 が a.method() を呼び出した場合、スレッド 2 は停止し、mutex ロックが解放されるまで待機します。

ついに、

class Foo {
public:
   void method(void) {
      mutex.lock();
      cout << "method called";
      // long computation
      mutex.unlock();
   }

private:
  static QMutex mutex;
};

QMutex Foo::mutex;

この場合、mutex はクラスの静的変数です。オブジェクト インスタンスごとにミューテックスのインスタンスが 1 つだけあります。上記の最初のケースと同じ状況 (2 つのスレッドと 2 つのインスタンス) があるとします。この場合、2 番目のスレッドが b.method() を呼び出そうとすると、最初のスレッドによって a.method() が完了するまで待機する必要があります。これは、ロックが一意になり、クラスのすべてのインスタンス間で共有されるためです。

詳細については、Qt にマルチスレッドに関する優れたチュートリアルがあります。

https://doc.qt.io/qt-5/threads.html

于 2009-08-02T16:41:54.367 に答える
2

ミューテックスは、スタック上でローカルにインスタンス化されます。したがって、1つのスレッドからf()を呼び出すと、ミューテックスの独自のインスタンスがロックされます。別のスレッドからf()を呼び出すと、それ自体がロックされます。したがって、g()からアクセスされたデータで競合状態が発生する可能性があります。同じクラスインスタンスで呼び出すのは難しいですが、次のようになります。

MyClass foo;
(In thread 1) foo->f();
(In thread 2) foo->f();

ロックをより適切に処理する方法は、何をしたいかによって異なります。あなたが言ったことによると、より良いポリシーはg()実装を直接変更することだと思います。たとえば、グローバルとして宣言されたミューテックス、またはg()の呼び出し間で共有されるようにg()で静的として宣言されたミューテックスをロックする必要があります。データをグローバルにロックしたいということを私が理解している限り、

于 2009-08-02T16:53:36.070 に答える