Initializing an anonymous instance of the mutex-lock-hold class in LHS comma

Suppose I have code like this:

#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; } 

If test_raiicomma_1 () was called from multiple threads, it blocks the mutex to prevent another thread from calling Func() at the same time. A mutex is locked when mut1_lock built and released when it goes out of scope and collapses.

This works fine, but depending on the style, I needed to give a name to the temporary object holding the lock. The test_raiicomma_2() function tries to avoid this by initializing the lock object and calling the Func() function within the same expression.

Is it true that the temporary object's destructor will not be called until the end of the expression after Func() returns? (If so, do you think itโ€™s ever worthwhile to use this idiom, or is it always clear to declare the lock in a separate statement?)

If it is necessary to lock two mutual values โ€‹โ€‹for the test_raiicomma_3() function, is it true that the mutexes will be locked in order before calling Func() and released later, but can, unfortunately, be released in any order?

+4
source share
3 answers

Is it true that the handle to the temporary object will not be called until the end of the expression after Func () returns?

It is guaranteed that both the constructor and the destructor are called, since they have side effects, and that destruction will occur only at the end of the full expression.

I think it should work

If the test_raiicomma_3 () function requires locking two mutexes, is it true that the mutexes will be locked in order before calling Func () and released later, but can, unfortunately, be released in any order?

Comma is always evaluated from left to right, and automatic variables within the scope are always destroyed in the reverse order of creation, so I think it is even guaranteed that they will be released in the (correct) order.

As stated in the comments, you need parentheses, or your expression will be parsed as an ad.

(If so, do you think it was ever worthwhile to use this idiom, or is it always clear to declare the lock in a separate statement?)

I donโ€™t think itโ€™s not, to the confusion for a very, very small gain ... I always use very explicit locks and very explicit areas (often additional {} inside the block), decent thread safety code is quite complicated without special code, and, on my opinion requires very clear code.

YMMW of course :)

+3
source

If you do not need to give meaningful names, you relieve you of the burden, he will add the task of figuring out what this code should do for the burden of the readers of your code - to decide whether test_raiicomma_3 will actually work as its writer intended.

Given that part of the code is written once, but read 10, 100 or 1000 times, is it really that difficult to write all the locks?

+3
source

Mutexes will be created in order from left to right and released at the end of the full expression. You can write:

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

The mutex will be destroyed in the correct order in accordance with the C ++ 5.18 / 1 standard:

The comma operator groups from left to right.
expression:
assignment expression
expression, assignment expression

A pair of expressions separated by a comma is evaluated from left to right, and the value of the left expression is discarded. The lvalue-to-rvalue parameter (4.1), the pointer array (4.2), and the standard conversion of the to-pointer function (4.3) sions do not apply to the left expression. All side effects (1.9) of the left expression, except the destruction of time series (12.2), are performed until the evaluation of the correct expression. The type and value of the result are the type and value of the right operand; the result is an lvalue if its right operand.

0
source

All Articles