Are non-mutating operations inherently thread safe (C ++)?

This is probably a dumb question, but consider the following pseudo-code:

struct Person { std::string name; }; class Registry { public: const std::string& name(int id) const {return _people[id].name;} void name(int id, const std::string& name) { [[scoped mutex]]; _people[id].name = name;} private: std::map<int, Person> _people; }; 

In this simple example, suppose the Registry is a singleton to which multiple threads will be available. I block during an operation that mutates data, but not during non-mutating access.

Is this thread safe, or should I also block during a read operation? I forbid several threads to try to change data at the same time, but I do not know what will happen if the thread tries to read while another wrote.

+4
source share
6 answers

You cannot safely read data while it is being modified. It is completely safe to have multiple threads reading data at once.

This difference is what read-write locks are for; they will allow any number of readers, but when the author tries to block the resource, new readers will no longer be allowed, and the writer will be blocked until all current readers are completed. Then the author will continue, and as soon as this is done, all readers will be allowed access again.

The reason it is not recommended to read data during modification is because the data may or may not be in a consistent state (for example, an object may temporarily not correspond to an invariant). If the reader reads it at this point, then it is just like there is a program error, unable to keep the data consistent.

 // example int array[10]; int size = 0; int &top() { return array[size-1]; } void insert(int value) { size++; top() = value; } 

Any number of threads can call top() at the same time, but if insert() running on one thread, then there is a problem when the strings alternate as follows:

 // thread calling insert thread calling top size++; return array[size-1]; array[size-1] = value 

The read stream receives garbage.

Of course, this is just one possible way that things can go wrong. In general, you cannot even assume that the program will behave as if lines of code on different threads would simply alternate. To make this assumption valid, the language simply tells you that you cannot have data races (that is, as we talked about, several threads accessing a (non-atomic) object with at least one thread modifying the object) *.

* And for completeness; that all atomic accesses use sequential memory matching. This is not important for you, since you are not doing low-level work directly with atomic objects.

+4
source

If any thread can modify the data, you need to block all access.

Otherwise, one of your read streams may access the data when it is in an undefined state. For example, changing a map requires several pointers. Your reading stream may receive a map, and some - but not all - of the map have been adjusted.

If you can guarantee that the data does not change, multiple reads from multiple threads do not need to be blocked, however this creates a fragile script that you will need to carefully monitor.

+7
source

Is this thread safe, or should I also block during a read operation?

It is not thread safe.

In paragraph 1.10 / 4 of the C ++ 11 standard:

Two evaluations of expressions conflict if one of them changes the memory location (1.7), and the other accesses or changes the same memory cell.

In addition, according to paragraph 1.10 / 21:

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

+3
source

This is not a safe thread.

A read operation can go through a map (this tree) to find the requested object, while a write operation suddenly adds or removes something from the map (or, even worse, the actual point where the iterator is).

If you are lucky, you will get an exception, otherwise it will just be undefined behavior while your card is in an unstable state.

0
source

I do not know what will happen if the thread tries to read at the same time another wrote.

No one knows. There is chaos.

Several threads can share a read-only resource, but as soon as someone wants to write it, it becomes unsafe for everyone to access it in any way until the recording is completed.

Why?

Pickets are not atomic . They occur within a few measures. A process trying to read an object as it is written may find a half-modified version, temporary garbage.

So

Block your readings if they match your record.

0
source

Totally unsafe!

If you change Person::Name from "John Smith" to "James Watt", you can read the meaning of "Jame Smith" or "James mith" well. Or, perhaps, even something completely different, because the way to "change this value for this" can not only copy new data to an existing place, but completely replace it with a new allocated part of the memory containing completely completely undefined content [including what is not a valid string].

0
source

All Articles