Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concurrent reads on non-atomic variable

I encounter this question while trying to implement a shared pointer. Let's focus on the managed data pointer. Its lifetime can be divided into three stages:

  1. Construction where there is no concurrent access.
  2. Concurrent reads on it (no writes).
  3. Destruction where there is no concurrent access. This is guaranteed by reference counting.

My question is, given this situation, is it necessary for the pointer to be atomic? I think it's equivalent to: will stage 2 lead to undefined behavior if the pointer is not atomic? Ideally, I want to hear an answer discussing from both a theoretical (language-lawyer) point of view and a practical point of view. For example, if not atomic, stage 2 may be undefined behavior theoretically, but is practically OK on actual platforms. For implementing shared pointer, if non-atomic is OK, the managed pointer can be unique_ptr<T>, otherwise it has to be atomic<T*>.

Update

I find the standard text (Section 1.10 p21):

The execution of a program contains a data race if it contains two conflicting actions in different threads, at least one of which is not atomic, and neither happens before the other. Any such data race results in undefined behavior.

I guess concurrent reads do not classify as conflicting actions. Could somebody find some standard text about this to be sure?

like image 431
Lingxi Avatar asked Feb 18 '18 18:02

Lingxi


2 Answers

Concurrent reads on any variable, whether atomic or not, do not constitute a data race, because of the definition of conflicting evaluations, found in [intro.multithread]:

Two expression evaluations conflict if one of them modifies a memory location and the other one accesses or modifies the same memory location.

Recently, this has moved to [intro.races] with a very subtle change in wording

Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location.

The change from accesses to reads took place between draft n4296 and n4431. The splitting of the multithreading section took place between n4582 and n4604.

like image 93
Ben Voigt Avatar answered Sep 30 '22 09:09

Ben Voigt


The rule is that if more than one thread accesses the same object at the same time and at least one of those threads is modifying the data, then you have a data race, and the behavior of the program is undefined. If nobody is modifying the object there is no problem from the concurrent accesses.

like image 30
Pete Becker Avatar answered Sep 30 '22 08:09

Pete Becker