6

What happens when in one thread write and in second thread read the same object? It would lead to application crash?

My idea is, on main thread save the data in to object or change the data from object and on second thread only read this data.

If I understand, the problem can be only while writing to object new value and reading in same time from same object, reading value will be old. But this is not problem for me.

I search my question and found this topic What happens if two threads read & write the same piece of memory but I am not sure if it apply for my question.

Wanderer
  • 319
  • 1
  • 3
  • 12

4 Answers4

10

Unless the object is atomic, the behaviour of one thread writing and another thread reading the same object is undefined.

Your current perception that the only issue is that state data could be read is not correct. You cannot assume that will be only manifestation of the undefined behaviour. In particular, you may well find that the value you read is neither the old nor the new value.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 7
    It is possibly worth mentioning that a particularly plausible failure is that a value will be read which is neither the old value or the new value. However, depending on the optimizer, the code could do absolutely anything. – Martin Bonner supports Monica Jun 12 '18 at 09:23
  • 1
    @MartinBonner Added. – Bathsheba Jun 12 '18 at 09:34
  • @Bathsheba To understand you, if object will be atomic then it will be ok? For example, 'std::atomic time_object;' reading and writing to this object on same time in different threads will not lead in to undefined behaviour? I am asking because your "Unless the object is atomic", can be translated (meaning) in my language either "if object is atomic, behaviour is undefined" or "if object is not atomic, behaviour is undefined". – Wanderer Jun 12 '18 at 12:57
2

It really depends on the size of the memory block you are trying to read and write from. If you are reading a single atomic data type then you can only read and write to the memory block as a whole (int as an example). You'll either non-deterministic-ally get the new or old value from the data type without any issues.

If you are reading and writing to a block of memory that isn't atomic, then during the reading cycle, some of the blocks can be overwritten and as such, the information can be corrupted. This will lead to some wild behavior and may cause breaks.

https://en.wikipedia.org/wiki/Linearizability

hi im Bacon
  • 374
  • 1
  • 12
  • The buried assumption that `int` is atomic is very naughty. – Bathsheba Jun 12 '18 at 09:34
  • Yeah, I felt bad saying it but https://www.google.co.uk/search?q=atomic+data+types&rlz=1C1GGRV_enGB801GB801&oq=atomic+data&aqs=chrome.0.69i59j69i57j69i60.2477j0j7&sourceid=chrome&ie=UTF-8 – hi im Bacon Jun 12 '18 at 10:10
  • You are also forgetting cache coherency issues. For example on ARM one core can write a value in a loop and another core can read a value and wait for it to change in a loop and never see a change. The write always goes to the L1 cache and is never flushed out and seen by the other cores cache. – Goswin von Brederlow Jun 12 '18 at 14:26
1

It is not safe. Consider using mutex to avoid memory corruption :

http://en.cppreference.com/w/cpp/thread/mutex

Artory
  • 845
  • 7
  • 13
-3

Generally the result is simply undefined. You have to do things to make it defined and you have a lot of docs to read.

  1. The compiler has to know that values might be changed from under it. Otherwise the optimizer will do the wrong thing and writes can be completely ignored. The keyword here is volatile. This is required when variables are changed from signal handlers or by the hardware itself. Not sufficient for multithreading.

  2. You must ensure that reads and writes are not interrupted. One way to do this is to use atomic types. The other is to protect access to a variable using locks or mutexes. Atomic types are limited in size by what the hardware supports so anything beyond simple integers or single pointers will require locks. The std::atomic type abstracts this away. It knows which types are atomic on your hardware and when it needs to use locking.

  3. Even that isn't enough since the timing of reads and writes is still random. If one thread writes and the other reads what will it read? Will the second thread read just before the first writes or just after? Even with all the right use of atomic or locks you don't know weather you will get the old or new value. If that matters you have to synchronize between the threads so the order of reads and writes becomes defined. Look for conditions.

Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42
  • `volatile` in C++ is very useful if you are dealing with memory mapped hardware that can change because of things happening. It is almost *no* use at all in handling multi-threaded C++. Also `std::atomic` works for any trivially copyable type (although it will internally have a mutex if the type is too large). – Martin Bonner supports Monica Jun 12 '18 at 09:41
  • 3
    `volatile` is not used for multithreading [Volatile and multithreading: Is the following thread-safe?](https://stackoverflow.com/questions/6592287/volatile-and-multithreading-is-the-following-thread-safe) – Bo Persson Jun 12 '18 at 09:41