Is the default copy constructor thread safe in C ++?

class CSample{ int a; // ..... lots of fields } Csample c; 

As you know, Csample has a default copy constructor. When I do this:

 Csample d = c 

a default copy constructor will be created. My question is: is it safe? Because maybe someone changes c in another thread when you execute the copy constructor. If so, how does the compiler do it? And if not, I think it's terrible that complier cannot guarantee that the copy constructor will be thread safe.

+6
source share
3 answers

Nothing in C ++ is thread-dependent¹ unless explicitly stated .

If you need to read object c while it can be modified in another thread, you are responsible for blocking it. This is a general rule, and there is no reason why reading it in order to create a copy should be an exception.

Please note that the created copy should not be blocked, because no other thread knows about it yet. Only the source should be.

The compiler does not guarantee that something can be thread safe, because 99.9% of things should not be thread safe. Most things only need to be repeated. Therefore, in the rare case, you really need to do something thread safe, you should use locks ( std::mutex ) or atomic types ( std::atomic<int> ).

You can also just make your objects persistent, and then you can read them without locking because nothing writes them after they are created. Code that uses persistent objects is more easily parallelized and more easily understood in general, because there are fewer things with state that you need to track.

Note that in the most common architecture, the mov command with int operands is thread safe. On other types of CPUs, even this may not be true. And since the compiler is allowed to preload values, an integer assignment in C ++ is not in any case.


¹ A set of operations is considered thread safe if it is correctly called on the same object2. In C ++, calling any modification operation and any other operation simultaneously on the same object is a data race, which is UndefinedBehavior ™.

² It is important to note that if the facility is "thread safe", this does not really help you in most cases. Because if the object guarantees that when it is written at the same time, you will always read the new or old value (C ++ allows you to read another stream, say 232 , when changing int c from 0 to 1000 , a large one Part of the time, this will not help you, because you need to read several values ​​in a consistent state, for which you still have to block them yourself.

³ Reentrant means that the same operation can be called up simultaneously on different objects. There are several functions in the C standard library that are not reentrant because they use global (static) buffers or some other state. Most of them have reentrant options (usually with the suffix _r ), and the standrd C ++ library uses them, so part of C ++ is usually reentrant.

+13
source

The general rule in the standard is simple: if an object (and sub-objects are objects) is accessible by more than one thread, and is changed by any thread, then all calls should be synchronized. There are many reasons for this, but most basic is that protection at the lowest level is usually the wrong level of detail ; adding synchronization primitives will make the code much slower, without any real advantage for the user, even in a multi-threaded environment. Even if the copy constructor was "thread safe", if the object is somehow independent of all other contexts, you probably need some sort of synchronization of the primitives at a higher level.

And with regard to "streaming security": the usual meaning among experienced practitioners is that the object / class / everything determines exactly what kind of protection it guarantees. Precisely because low-level definitions like you (and many, many others) seem to be worthless. Synchronizing each function in a class is usually useless. (Java did an experiment and then backtracked because the supporters they made in the initial version of their containers turned out to be expensive and cost nothing.)

+5
source

Assuming d or c accessed simultaneously on multiple threads, this is not thread safe. This will mean a data race that is undefined.

 Csample d = c; 

as dangerous as

 int d = c; 

there is.

+1
source

Source: https://habr.com/ru/post/973151/


All Articles