4

次のようなコードがあるとします。

#include "boost/thread/mutex.hpp"

using boost::mutex;
typedef mutex::scoped_lock lock;

mutex mut1, mut2;

void Func() {
 // ...
}

void test_raiicomma_1() {
 lock mut1_lock(mut1);
 Func();
}

void test_raiicomma_2() {
 (lock(mut1)), Func();
}

void test_raiicomma_3() {
 (lock(mut1)), (lock(mut2)), Func(); // Warning!
}

int main()
{
 test_raiicomma_1();
 test_raiicomma_2();
 test_raiicomma_3();
 return 0;
}

関数test_raiicomma_1()が複数のスレッドから呼び出された場合、ミューテックスをロックして、他のスレッドも同時に呼び出さFunc()れないようにします。ミューテックスは、変数mut1_lockが作成されるとロックされ、スコープから外れて破棄されると解放されます。

これは完全に正常に機能しますが、スタイルの問題として、ロックを保持している一時オブジェクトに名前を付ける必要があると、私はイライラしました。関数test_raiicomma_2()は、ロックオブジェクトを初期化し、1つの式内で関数を呼び出すことにより、これを回避しようとしますFunc()

Func()一時オブジェクトデストラクタは、式が戻った後、式が終了するまで呼び出されないというのは正しいですか?(もしそうなら、このイディオムを使用する価値があると思いますか、それとも別のステートメントでロックを宣言する方が常に明確ですか?)

関数test_raiicomma_3()が2つのミューテックスをロックする必要がある場合、ミューテックスが呼び出す前に順番にロックされ、Func()後で解放されるのは正しいですか?残念ながら、どちらの順序でも解放される可能性がありますか?

4

3 に答える 3

4

Func() が戻った後、式の最後まで一時オブジェクト デストラクタが呼び出されないというのは正しいですか?

コンストラクタとデストラクタには副作用があるため、両方が呼び出されることが保証されており、破壊は完全な式の最後でのみ発生します。

私はそれがうまくいくはずだと信じています

関数 test_raiicomma_3() が 2 つのミューテックスをロックする必要がある場合、ミューテックスは Func() を呼び出す前に順番にロックされ、後で解放されますが、残念ながらどちらの順序でも解放される可能性がありますか?

コンマは常に左から右に評価され、スコープ内の自動変数は常に作成の逆順で破棄されるため、(正しい) 順序で解放されることも保証されていると思います

litb がコメントで指摘しているように、中かっこが必要です。そうしないと、式が宣言として解析されます。

(そうであれば、このイディオムを使用する価値があると思いますか? それとも、別のステートメントでロックを宣言する方が常に明確ですか?)

私はそうは思いません。非常にわずかな利益のために混乱を招く...私の意見では、非常に明確なコードを保証します。

もちろんYMMW:)

于 2009-09-08T11:49:42.927 に答える
3

test_raiicomma_3意味のある名前を付ける必要がないことで負担が軽減されますが、そのコードが何をすべきかを調べるタスクが追加され、コードの読者の負担になります。想定していたようです。

コードの一部が 1 回書かれ、10 回、100 回、または 1000 回読み取られるとすれば、すべてのロックを作成するのは本当に難しいのでしょうか?

于 2009-09-08T11:43:50.460 に答える
0

ミューテックスは左から右の順序で作成され、完全な式の最後に解放されます。あなたは書くことができます:

 // parentheses tells that it is full expression and set order explicitly
 ( ( lock(mut1), lock(mut2) ), Func() ); 

ミューテックスは、C++ 標準 5.18/1 に従って適切な順序で破棄されます。

コンマ演算子は左から右にグループ化します。
式:
代入式
式 、代入式

コンマで区切られた式のペアは左から右に評価され、左側の式の値は破棄されます。左辺値から右辺値 (4.1)、配列からポインタ (4.2)、および関数からポインタ (4.3) への標準変換は、左側の式には適用されません。一時変数の破棄 (12.2) を除く、左の式のすべての副作用 (1.9) は、右の式の評価の前に実行されます。結果の型と値は、右側のオペランドの型と値です。右オペランドが左辺値の場合、結果は左辺値です。

于 2009-09-08T11:45:00.613 に答える