I have recently come across a curious use of the volatile keyword in C++ multithreaded code. To abstract the programming pattern, let's assume there is a control object which is accessed by one producer and several consumer threads:
class control_t {
pthread_mutex_t control_lock;
pthread_cond_t wake_cond;
bool there_is_work_todo;
control_t volatile* vthis() { return this; }
}
The consumer thread does the following (c is a non-volatile pointer to the control object):
...
pthread_mutex_lock(c->control_lock)
while (!c->vthis()->there_is_work_todo) {
pthread_cond_wait(&c->wake_cond, &c->control_lock);
}
...
The idea here is that the consumer threads will wait until there is some work to be done, which the producer signalizes via the wake_cond variable.
What I don't understand here is why the control object is accessed through a volatile pointer to "this", which is returned by the method vthis(). Why is that?
The use of volatile
in multi-threaded code is generally suspect. volatile
was designed to avoid optimizing out reads and writes to memory, which is useful when such reads and writes occur on special addresses that map to hardware registers. See, for example, how volatile
is useless to prevent data-races, and how it can be (ab)used as a phantom type...
Since the author used proper synchronization (mutexes and condition variables), the use of of volatile
is extremely suspect. Such uses generally stem from a misunderstanding, most notably spread by languages such as Java who reused the same keyword with different semantics.
In C and C++, multi-threaded code should rely on memory barriers, such as those introduced by the mutexes and atomic operations, which guarantee that the values are correctly synchronized across the different CPU cores and caches.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments