Francis Cugler
Francis Cugler

Reputation: 7895

What is the prefered way of using lock guard and mutex

A class member function will use a mutex and lock_guard on its critical section or critical data. I can see that this can be done in 2 different ways.

Case 1: - Inside of for loop. lock_guard is constructed and destructed on each iteration.

std::mutex s_mutex;

class Foo {
public:
    void bar() {
        for ( ... ) {
            std::lock_guard<std::mutex> guard( s_mutex );
            // critical section data
        } // lock_guard goes out of scope and releases or unlocks mutex
    }
};

Case 2: - Outside of for loop. lock_guard is created once and then destroyed after loop completes.

std::mutex s_mutex;

class Foo {
public:
    void bar() {
        std::lock_guard<std::mutex> guard( s_mutex );
        for ( ... ) {
            // data
        }
    } // lock_guard goes out of scope releasing or unlocking mutex.
};

I do know that in the first case one thread can access the loop on one iteration while a different thread can access the loop on a different iteration, but no two threads can simultaneously access the critical section. And as for the second case I do know that if a thread is accessing the loop, a second thread can not touch that loop until it finishes fully.

Is one method more desirable over the other or does it depend on the intention of use? Is there a performance impact one over the other? Just want some clarification for trying to maintain modern c++ best practices.

Upvotes: 0

Views: 1141

Answers (1)

user1143634
user1143634

Reputation:

You are unlocking the mutex to lock it immediately afterwards. What happens depends on how mutex is implementated, but typical non-fair implementation will awake one waiting thread, but will grab the mutex before that thread is able to run, wasting execution time.

If your mutex implementation is fair (think of ticket lock), then your thread won't be able to lock the mutex after unlocking it and will have to wait until another thread leaves the critical section. That means under contention your thread will have to do a context switch at every iteration, wasting execution time.

So the second case (mutex outside the loop) should be more efficient with both fair and non-fair mutex implementation and this is what you should do.

Now you might consider locking the mutex at every iteration if you care about latency, as this allows other threads to run, but this only makes sense with fair mutex implementation.

C++ does not say anything about whether std::mutex is fair or not and most implementations are not fair. So don't expect much from it.

So the only sane and portable way is to put the lock outside the loop. Because even if you care about latency, std::mutex is not something that can help you.

Upvotes: 5

Related Questions