4

If I am accessing shared memory for reading only, to check a condition for an if() block, should I still lock the mutex? E.g.

mutex_lock();

if (var /* shared memory */) {

}

mutex_unlock();

Is locking here needed and good practice?

Iceman
  • 4,202
  • 7
  • 26
  • 39
  • 1
    Off-topic, but it would be a very good idea to lock the mutex using an RAII-style `lock` class which unlocks it in its destructor, like `std::lock_guard` does. Otherwise, there's a danger that returning early or throwing an exception could leave it locked forever. – Mike Seymour Apr 01 '13 at 16:19

1 Answers1

4

If the variable you are reading could be written to concurrently, then yes, you should acquire a lock on the mutex.

You could only read it atomically if your compiler provides you with the necessary primitives for that; this could be either the atomic features that come with C11 and C++11 or some other language extension provided by your compiler. Then you could move the mutex acquisition into the conditional, but if you wait until after the test to acquire the mutex then someone else may change it between the time you test it and the time you acquire the mutex:

if (example) {
    // "example" variable could be changed here by another thread.

    mutex_lock();

    // Now the condition might be false!

    mutex_unlock();
}

Therefore, I would suggest acquiring the mutex before the conditional, unless profiling has pinpointed mutex acquisition as a bottleneck. (And in the case where the tested variable is larger than a CPU register -- a 64-bit number on a 32-bit CPU, for example -- then you don't even have the option of delaying mutex acquisition without some other kind of atomic fetch or compare primitive.)

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • 2
    a nitpick: "read it with defined behavior" is not exactly correct. According to the C++11 standard the value returned for a read of a non-atomic involved in a data race is _undefined_. (And C++ and C specs prior to 2011 did not define the semantics of multithreaded programs at all.) Also: the variable needs to fit into one CPU register, _and be aligned_ according to the rules of your architecture and compiler for you to be able to predict what the undefined value might be. – Wandering Logic Apr 01 '13 at 14:11
  • 4
    @WanderingLogic - **and** you have to have appropriate barriers to ensure that caches are updated, and appropriate compiler barriers to guard against code movement for optimization. In short: if you haven't used an atomic type, don't try to treat something atomically. – Pete Becker Apr 01 '13 at 15:33
  • @WanderingLogic, I wouldn't call this a nitpick. That part of the answer is really bad advice. Trying such tricks without really knowing everything (how these things work, specifics of the architecture) can lead to bugs that are very hard to find. – Jens Gustedt Apr 01 '13 at 16:26
  • I've tagged this answer as a community wiki -- feel free to edit these suggestions into the answer. It wouldn't be fair of me to gain reputation from changes this fundamental. – cdhowie Apr 01 '13 at 17:50
  • This does not answer the question, that is all about **reading**. – ntd Jul 12 '17 at 09:23