10

I am new to using threads and have read a lot about how data is shared and protected. But I have also not really got a good grasp of using mutexes and locks to protect data.

Below is a description of the problem I will be working on. The important thing to note is that it will be time-critical, so I need to reduce overheads as much as possible.

I have two fixed-size double arrays.

  • The first array will provide data for subsequent calculations. Threads will read values from it, but it will never be modified. An element may be read at some time by any of the threads.

  • The second array will be used to store the results of the calculations performed by the threads. An element of this array will only ever be updated by one thread, and probably only once when the result value
    is written to it.

My questions then:

  1. Do I really need to use a mutex in a thread each time I access the data from the read-only array? If so, could you explain why?

  2. Do I need to use a mutex in a thread when it writes to the result array even though this will be the only thread that ever writes to this element?

  3. Should I use atomic data types, and will there be any significant time overhead if I do?

  4. Many answers to this type of question seem to be - no, you don't need the mutex if your variables are aligned. Would my array elements in this example be aligned, or is there some way to ensure they are?

The code will be implemented on 64bit Linux. I am planning on using Boost libraries for multithreading.

I have been mulling this over and looking all over the web for days, and once posted, the answer and clear explanations came back in literally seconds. There is an "accepted answer," but all the answers and comments were equally helpful.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
BarbieBear
  • 175
  • 3
  • 10
  • 1
    The purpose of locks is to prevent one concurrent task from modifying data while another task is using it. For the input array, the data is immutable (no threads modify it), so you don't need to lock that. – Colonel Thirty Two Jun 10 '15 at 14:12
  • 2
    If you indeed hold those predicates in your description, I see no need for locks nor atomics whatsoever. – WhozCraig Jun 10 '15 at 14:21
  • as for question 4: Your array (obviously) need to be aligned to satisfy its type, and will be by default. However, you may want to additionally align to cache lines (normally 64 bytes) and you probably really want to avoid false sharing: http://en.wikipedia.org/wiki/False_sharing – Arvid Jun 11 '15 at 13:34

4 Answers4

7
  1. Do I really need to use a mutex in a thread each time I access the data from the read-only array? If so could you explain why?

No. Because the data is never modified, there cannot be synchronization problem.

  1. Do I need to use a mutex in a thread when it writes to the result array even though this will be the only thread that ever writes to this element?

Depends.

  1. If any other thread is going to read the element, you need synchronization.
  2. If any thread may modify the size of the vector, you need synchronization.

In any case, take care of not writing into adjacent memory locations by different threads a lot. That could destroy the performance. See "false sharing". Considering, you probably don't have a lot of cores and therefore not a lot of threads and you say write is done only once, this is probably not going to be a significant problem though.

  1. Should I use atomic data types and will there be any significant time over head if I do?

If you use locks (mutex), atomic variables are not necessary (and they do have overhead). If you need no synchronization, atomic variables are not necessary. If you need synchronization, then atomic variables can be used to avoid locks in some cases. In which cases can you use atomics instead of locks... is more complicated and beyond the scope of this question I think.

Given the description of your situation in the comments, it seems that no synchronization is required at all and therefore no atomics nor locks.

  1. ...Would my array elements in this example be aligned, or is there some way to ensure they are?

As pointed out by Arvid, you can request specific alignment using the alginas keyword which was introduced in c++11. Pre c++11, you may resort to compiler specific extensions: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Variable-Attributes.html

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Just to confirm (based on answers 1. and 2) - no other thread will read or write to that array element during these calculations and the array sizes are fixed, so no mutexes needed for the writing array? – BarbieBear Jun 10 '15 at 14:16
  • 1
    @KirilKirov if thread A modifies `x[0]` and thread B modifies `x[i]` where `i != 0` are you sure that synchronization is required? – eerorika Jun 10 '15 at 14:17
  • Oh, sorry, I've missed "that ever writes to this element". Ignore my comment. – Kiril Kirov Jun 10 '15 at 14:18
  • @BarbieBear But is the element the threads will modify predetermined before the threads start? Or will the thread pick one element when it's ready to write the result? In the former case, you don't need locking as no two threads will write to the same elements, but in the latter case you do need locking or two (or more) threads might otherwise pick the same element. – Some programmer dude Jun 10 '15 at 14:20
  • So if I don't need mutexes for the two array, do I need to bother with using atomic variables, or is there some benefit in doing so? – BarbieBear Jun 10 '15 at 14:21
  • @BarbieBear given your description of the situation, no synchronization seem to be required so there is no benefit from atomics. – eerorika Jun 10 '15 at 14:23
  • @Joachim Pileborg. The array element will be predetermined before hand, so can guarantee that only one thread can write to a given element. – BarbieBear Jun 10 '15 at 14:25
  • @BarbieBear Then no synchronization is needed, neither locks, mutexes nor atomics. – Some programmer dude Jun 10 '15 at 14:27
  • @BarbieBear atomics have their place, but from your description that place isn't in your task. if you were, for example, using a reference to an "index" variable that was picked up by each thread to obtain its target array slot, where each thread bumped and grabbed the index value, *that* would be a stellar place for an atomic. But you stated even your target slot(s) are predetermined *and* unique per-thread. I don't see any need for concurrency restrictions at all, because frankly as you described it there is no data-concurrency whatsoever. – WhozCraig Jun 10 '15 at 14:28
  • 1
    it is possible to affect alignment with the alignas specifier. http://en.cppreference.com/w/cpp/language/alignas – Arvid Jun 11 '15 at 13:30
  • @Arvid thanks for pointing that out. I forgot it was added in c++11. I'll change the answer. – eerorika Jun 11 '15 at 18:26
4

Under the two conditions given, there's no need for mutexes. Remember every use of a mutex (or any synchronization construct) is a performance overhead. So you want to avoid them as much as possible (without compromising correct code, of course).

  1. No. Mutexes are not needed since threads are only reading the array.

  2. No. Since each thread only writes to a distinct memory location, no race condition is possible.

  3. No. There's no need for atomic access to objects here. In fact, using atomic objects could affect the performance negatively as it prevents the optimization possibilities such as re-ordering operations.

P.P
  • 117,907
  • 20
  • 175
  • 238
1

The only time you need to use Locks is when data is modified on a shared resource. Eg if some threads where used to write data and some used to read data (in both cases from the same resource) then you only need a lock for when writing is done. This is to prevent whats known as "race".

There is good information of race on google for when you make programs that manipulate data on a shared resource.

snyggt
  • 9
  • 7
0

You are on the right track.

1) For the first array (read only) , you do not need to utilize a mutex lock for it. Since the threads are just reading not altering the data there is no way a thread can corrupt the data for another thread

2) I'm a little confused by this question. If you know that thread 1 will only write an element to array slot 1 and thread 2 will only write to array slot 2 then you do not need a mutex lock. However I'm not sure how your achieving this property. If my above statement is not correct for your situation you would definitely need a mutex lock.

3) Given the definition of atomic:

Atomic types are types that encapsulate a value whose access is guaranteed to not cause data races and can be used to synchronize memory accesses among different threads.

Key note, a mutex lock is atomic meaning that there is only 1 assembly instruction needed to grab/release a lock. If it required 2 assembly instructions to grab/release a lock, a lock would not be thread safe. For example, if thread 1 attempted to grab a lock and was switched to thread 2, thread 2 would grab the lock.

Use of atomic data types would decrease your overhead but not significantly.

4) I'm not sure how you can assure your variables are lined. Since threads can switch at any moment in your program (Your OS determines when a thread switches)

Hope this helps

Richard Mpanga
  • 3
  • 1
  • 1
  • 4