Tmx
Tmx

Reputation: 597

Any multi-thread concern on memcpy function?

memcpy(a, b, sizeof(a));

v.s.

a[0] = b[0];
a[1] = b[1];
...

Suppose that memcpy should have smaller code size and high efficiency, but is there any risk to memcpy in multi-thread system?

Upvotes: 3

Views: 4039

Answers (3)

Star Brilliant
Star Brilliant

Reputation: 3126

Long story short:

Both code is the same to the compiler, and even compiles exactly to the same assembly code at optimization level clang -O1, gcc -O2 or higher.

Explanation:

Modern C doesn’t enforce “sequentially consistent ordering”, which allows certain reordering to happen:

  1. The compiler can freely swap the order of a[0] = b[0]; and a[1] = b[1]; if the compiler knows abs(a - b) ≥ sizeof a / sizeof a[0].
  2. Even if the compiler doesn’t do that, the CPU can freely swap the order of them as well.
  3. Even if the CPU successfully writes data to the memory, another thread may not read the latest copy of that data.

If you want to prevent 1 from happening, you need to insert a compiler fence (e.g., asm("" ::: "memory");.

Similarly, if you want to prevent 2 and 3 from happening, you need to insert a memory fence (e.g., atomic_thread_fence) or use a mutex which produces an appropriate memory fence whenever you lock or unlock it.

Observing the side-effects of any non-atomic operation from another thread without an appropriate synchronization mechanism is undefined behavior.

Based on the above assumptions, the compiler can freely make these two transformations:

  1. Transform your whole a[0] = b[0]; … sequence into a memcpy, if the compiler knows a and b doesn’t overlap.
  2. Transform your whole a[0] = b[0]; … sequence into a memmove, if the compiler knows a ≤ b.
  3. Transform your whole a[0] = b[0]; … sequence into some SIMD instructions so both statements are executed in parallel, if the compiler knows a and b doesn’t overlap within the distance of a SIMD vector length.
  4. Similarly, the compiler can also do the transformation in reverse if sizeof a is small.

Therefore, to the compiler, there is no difference. No matter whether your program is single-threaded or multi-threaded.

Upvotes: 0

AnT stands with Russia
AnT stands with Russia

Reputation: 320541

  1. If the buffers are exclusive, meaning that threads are not competing for access to the data involved in the copying, then memcpy is perfectly safe to use in multi-threaded environment. The function has no persistent state and no other side-effects besides modifying the target buffer.

  2. Also, you can safely perform muti-threaded copying from a buffer shared by any number of threads, as long as no thread attempts to change that buffer.

  3. But once there's a competition between the threads for writing into any shared buffers, memcpy no longer guarantees thread safety, i.e. the operation is not atomic. Aside from what is described in 2, two simultaneous memcpys operating on the same buffer will interfere with each other and produce unpredictable results.

Upvotes: 7

cwfighter
cwfighter

Reputation: 502

If you do not use lock to ensure exclusive, using memcpy() only will be very dangerous! The memcpy() is only responsible for copying memory, don't ensure thread safe, you should add lock by yourself. In C language, in user's space, you can use mutex for ensuring exclusive.

Upvotes: 1

Related Questions