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.