6

Let's say I have the following function.

std::mutex mutex;

int getNumber()
{
    mutex.lock();
    int size = someVector.size();
    mutex.unlock();
    return size;
}

Is this a place to use volatile keyword while declaring size? Will return value optimization or something else break this code if I don't use volatile? The size of someVector can be changed from any of the numerous threads the program have and it is assumed that only one thread (other than modifiers) calls getNumber().

Etherealone
  • 3,488
  • 2
  • 37
  • 56
  • 2
    There is an explanation of volatile here: http://stackoverflow.com/questions/154551/volatile-vs-interlocked-vs-lock – Will May 04 '13 at 17:42
  • 5
    @Will I don't think the C# `volatile` is the same as the C++ `volatile` (though it would be useless in both languages in this situation). – John Calsbeek May 04 '13 at 17:47
  • 1
    Ooops, I didn't see that answer was for C++. Here is a better explanation of volatile: http://stackoverflow.com/questions/72552/why-does-volatile-exist – Will May 04 '13 at 17:54
  • possible duplicate of [does presence of mutex help getting rid of volatile key word ?](http://stackoverflow.com/questions/1616093/does-presence-of-mutex-help-getting-rid-of-volatile-key-word) – BЈовић May 04 '13 at 22:07

3 Answers3

8

No. But beware that the size may not reflect the actual size AFTER the mutex is released.

Edit:If you need to do some work that relies on size being correct, you will need to wrap that whole task with a mutex.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • The function is only used as a hint for now so precision is not really needed at the moment. Thanks for the heads up though. – Etherealone May 04 '13 at 17:58
5

You haven't mentioned what the type of the mutex variable is, but assuming it is an std::mutex (or something similar meant to guarantee mutual exclusion), the compiler is prevented from performing a lot of optimizations. So you don't need to worry about return value optimization or some other optimization allowing the size() query from being performed outside of the mutex block.

However, as soon as the mutex lock is released, another waiting thread is free to access the vector and possibly mutate it, thus changing the size. Now, the number returned by your function is outdated. As Mats Petersson mentions in his answer, if this is an issue, then the mutex lock needs to be acquired by the caller of getNumber(), and held until the caller is done using the result. This will ensure that the vector's size does not change during the operation.


Explicitly calling mutex::lock followed by mutex::unlock quickly becomes unfeasible for more complicated functions involving exceptions, multiple return statements etc. A much easier alternative is to use std::lock_guard to acquire the mutex lock.

int getNumber()
{
    std::lock_guard<std::mutex> l(mutex); // lock is acquired
    int size = someVector.size();
    return size;
} // lock is released automatically when l goes out of scope
Community
  • 1
  • 1
Praetorian
  • 106,671
  • 19
  • 240
  • 328
1

Volatile is a keyword that you use to tell the compiler to literally actually write or read the variable and not to apply any optimizations. Here is an example

int example_function() {
int a;
volatile int b;
a = 1; // this is ignored because nothing reads it before it is assigned again
a = 2; // same here
a = 3; // this is the last one, so a write takes place 
b = 1; // b gets written here, because b is volatile
b = 2; // and again
b = 3; // and again
return a + b; 
}

What is the real use of this? I've seen it in delay functions (keep the CPU busy for a bit by making it count up to a number) and in systems where several threads might look at the same variable. It can sometimes help a bit with multi-threaded things, but it isn't really a threading thing and is certainly not a silver bullet

Will
  • 805
  • 1
  • 9
  • 26