It is not as simple as it may seem, except in two cases:
- When there are only readers and no writers, you need to not sync.
- When writing multiple threads, and at least one of them performs a read-modify-write operation (for example,
++x; ), you need to always synchronize, or you will get completely unpredictable results.
In all other cases, if you have at least one writer and reader (or several authors), you usually (with very few exceptions) should synchronize access, but not always, and not always in the most strict way.
It depends on what kind of warranty you need. Some applications require a strict consistent consistency across threads (and sometimes even block integrity is needed). Some applications will work equally well, but with much greater performance, if they only happen - before guarantees in a single thread. However, other applications do not even need it and are completely satisfied with relaxed operations or without any guarantees whatsoever.
For example, this “typical” workflow implementation has an author and a reader:
// worker thread running = true; while(running) { task = pull_task(); execute(task); } // main thread exit code running = false; join(workerthread);
This works fine, without any synchronization. Yes, pedantically speaking, it is undefined when and how the running value will change, but in fact it does not matter. It is impossible for the memory location to have any “random” intermediate value, and it really doesn’t matter if the change becomes visible several tens of nanoseconds sooner or later, because the workflow is likely to be busy with the task in any in the worst case, it picks up the change a few milliseconds later. In the end, at the next iteration, the workflow will pick up the change and exit.
SPSC fast forward, published in Dr. Dobb several years ago, worked on a similar principle, only with pointers.
A good and comprehensive introduction to the various synchronization modes and their consequences is given in the GCC documentation .
source share