I am writing a Multithreaded application. That application contains an array of length, lets say, 1000.
If I now would have two threads and I would make sure, that thread 1 will only access the elements 0-499 and thread 2 would only access elements 500-999, would I need a locking mechanism to protect the array or would that be fine.
Note: Only the content of the array will be changed during calculations! The array wont be moved, memcpyed or in some other way altered than altering elements inside of the array.
What you want is perfectly fine! Those kind of strategies (melt together with a bunch of low level atomic primitives) are the basis for what's called lock-free programming.
Actually, there could be possible problems in implementing this solution. You have to strongly guarantee the properties, that you have mentioned.
Make sure, that your in memory data array never moves. You cannot rely on most std containers. Most of them could significantly change during modification. std::map are rebalancing inner trees and making some inner pointers invalid. std::vector sometimes reallocates the whole container when inserting.
Make sure that there is only one consumer and only one producer for any data, that you have. Each consumer have to store inner iterator in valid state to prevent reading same item twice, or skip some item. Each producer must put data in valid place, without possibility to overwrite existing, not read data.
Disobeying of any of this rules makes you need to implement mutexes.
Related
Lets say I have a vector of int which I've prefilled with 100 elements with a value of 0.
Then I create 2 threads and tell the first thread to fill elements 0 to 49 with numbers, then tell thread 2 to fill elements 50 to 99 with numbers. Can this be done? Otherwise, what's the best way of achieving this?
Thanks
Yes, this should be fine. As long as you can guarantee that different threads won't modify the same memory location, there's no problem.
Yes, for most implementations of vector, this should be ok to do. That said, this will have very poor performance on most systems, unless you have a very large number of elements and you are accessing elements that are far apart from each other so that they don't live on the same cache line... otherwise, on many systems, the two threads will invalidate each other's caches back-and-forth (if you are frequently reading/writing to those elements), leading to lots of cache misses in both threads.
Since C++11:
Different elements in the same container can be modified concurrently
by different threads, except for the elements of std::vector< bool>
(for example, a vector of std::future objects can be receiving values
from multiple threads).
cppreference discusses the thread safety of containers here in good detail.
Link was found in a Quora post.
The fact that "vector is not thread-safe" doesn't mean anything.
There's no problem with doing this.
Also you don't have to allocate your vector on heap (as one of the answers suggested). You just have to ensure that the lifetime of your vector covers the lifetime of your threads (more precisely - where those threads access the vector).
And, of course, since you want your both threads to work on the same vector - they must receive it from somewhere by pointer/reference rather than by value.
There's also absolutely no problem to access the same element of the array from within different threads. You should know however that your thread is not the only one that accesses it, and treat it respectively.
In simple words - there's no problem to access an array from within different threads.
Accessing the same element from different thread is like accessing a single variable from different thread - same precautions/consequences.
The only situation you have to worry about is when new elements are added, which is impossible in your case.
There is no reason why this cannot be done. But, as soon as you start mixing accesses (both threads accessing the same element) it becomes far more challenging.
vector is not thread safe. You need to guard the vector between threads. In your case it depends on vector implementation. If the vector internal data is accessed\modified from different threads, it purely depends on vector impl.
With arrays it can be done for sure (the threads do not access the same memory area); but as already noted, if you use the std::vector class, the result may depend on how it is implemented. Indeed I don't see how the implementation of [] on the vector class can be thread unsafe (provided the threads try to access different "indexes"), but it could be.
The solution is: stick to the use of an array, or control the access to the vector using a semaphore or similar.
What you describe is quite possible, and should word just fine.
Note, however, that the threads will need to work on a std::vector*, i.e. a pointer to the original vector---and you probably should allocate the vector on the heap, rather than the stack. If you pass the vector directly, the copy constructor will be invoked and create a separate copy of the data on each thread.
There are also lots of more subtle ways to get this wrong, as always with multithreaded programming. But in principle what you described will work well.
This should be fine, but you would end up with poor performance due to false sharing where each thread can potentially invalidate each other's cache line
I have a program where multiple threads share the same data structure which is basically a 2D array of vectors and sometimes two or more threads might have to insert at the same position i.e. vector which might result in a crash if no precautions were taken. What is the fastest and most efficient way to implement a safe solution for this issue ? Since this issue does not happen very often (no high contention) I had a 2D array of mutexes where each mutex maps to a vector and then each thread locks then unlocks the mutex after finishing from updating the corresponding vector. If this is a good solution, I would like to know if there is something faster than mutex to use.
Note, I am using OpenMP for the multithreading.
The solution greatly depends on how the problem is. For example:
If the vector size may exceed its capacity (i.e. reallocation is required).
Whether the vector is only being read, elements are being inserted or elements can be both inserted and removed.
In the first case, you don't have any other possibility than using locks, since you always need to check whether the vector is being reallocated, and wait for the reallocation to complete if necessary.
On the other hand, if you are completely sure that the vector is only initialized once by a single thread (which is not your case), probably you would not need any synchronization mechanism to perform access to vector elements (inside-element access synchronization may still be required though).
If elements are being inserted and removed from the back of the vector only (queue style), then using atomic compare and swap would be enough (atomically increase the size of the vector, and insert in position size-1 when the swap was successful.
If elements may be removed at any point of the vector, its contents may need to be moved to remove empty holes. This case is similar to a reallocation. You can use a customized heap to manage the empty positions in your vector, although this will increase the complexity.
At the end of the day, probably you will need to either develop your own parallel data structure or rely on a library, such as TBB or Boost.
If I have 10 threads, and an array of 10 sub-arrays, is it safe to have each thread do work on a different one of the sub-arrays? i.e. thread[0] does stuff to array[0], thread[1] does stuff to array[1], etc. Or is this not safe to do? Does it make a difference if it's a vector or array (or any data set for that matter)?
Yes, you're safe. As long as none of the threads modifies a resource other threads access without guards or syncing you're safe. It doesn't matter if the memory addresses are very close to each other; proximity doesn't play a role. All that matters is whether there's sharing, and if so does any of the threads modify the shared resource.
Yes, but beware of false sharing.
Essentially yes - it is safe at the array level (but it may also depend - see below). However, if it were another structure, for example a tree or a doubly-linked list, then you may run into issues if you try to modify the structure since a change to one element may require changes to other elements as well which is not safe. But as long as you are only reading the data, you should be OK. One possible pitfall is if the array contains references or pointers. In this case it may happen that while you are accessing separate array entries, the are directly or indirectly referencing the same areas in memory. In that case, you must perform proper synchronization.
So in one word: if it's an array of int or another simple data type, you are completely safe. If it's not an array or the elements are not completely in-place but contain pointers or references, you should be careful.
If you create a "mother-array" which contains 10 smaller arrays and each thread is accessing one of those arrays exclusively then nothing bad can happen. The size of the elements of those arrays does not matter.
If you use more complex structures instead of arrays, if reading does not change anything then you are safe too. However, if a simple read from the structure can modify it (e.g. something is cached, reorganised), having parallel threads accessing the mother-structure can be problematic.
Apart from that - I don't see any case when this could cause trouble.
Let's say I have a vector of N elements, but up to n elements of this vector have meaningful data. One updater thread updates the nth or n+1st element (then sets n = n+1), also checks if n is too close to N and calls vector::resize(N+M) if necessary. After updating, the thread calls multiple child threads to read up to nth data and do some calculations.
It is guaranteed that child threads never change or delete data, (in fact no data is deleted what so ever) and updater calls children just after it finishes updating.
So far no problem has occured, but I want to ask whether a problem may occur during reallocating of vector to a larger memory block, if there are some child working threads left from the previous update.
Or is it safe to use vector, as it is not thread-safe, in such a multithreaded case?
EDIT:
Since only insertion takes place when the updater calls vector::resize(N+M,0), are there any possible solutions to my problem? Due to the great performance of STL vector I am not willing to replace it with a lockable vector or in this case are there any performant,known and lock-free vectors?
I want to ask whether a problem may occur during reallocating of vector to a larger memory block, if there are some child working threads left from the previous update.
Yes, this would be very bad.
If you are using a container from multiple threads and at least one thread may perform some action that may modify the state of the container, access to the container must be synchronized.
In the case of std::vector, anything that changes its size (notably, insertions and erasures) change its state, even if a reallocation is not required (any insertion or erasure requires std::vector's internal size bookkeeping data to be updated).
One solution to your problem would be to have the producer dynamically allocate the std::vector and use a std::shared_ptr<std::vector<T> > to own it and give this std::shared_ptr to each of the consumers.
When the producer needs to add more data, it can dynamically allocate a new std::vector with a new, larger size and copies of the elements from the old std::vector. Then, when you spin off new consumers or update consumers with the new data, you simply need to give them a std::shared_ptr to the new std::vector.
Is how your workers decide to work on data thread safe? Is there any signaling between workers done and the producer? If not then there is definitely an issue where the producer could cause the vector to move while it is still being worked on. Though this could trivially be fixed by moving to a std::deque instead.(note that std::deque invalidates iterators on push_back but references to elements are not affected).
I've made my own GrowVector. It works for me and it is really fast.
Link: QList, QVector or std::vector multi-threaded usage
Lets say I have a vector of int which I've prefilled with 100 elements with a value of 0.
Then I create 2 threads and tell the first thread to fill elements 0 to 49 with numbers, then tell thread 2 to fill elements 50 to 99 with numbers. Can this be done? Otherwise, what's the best way of achieving this?
Thanks
Yes, this should be fine. As long as you can guarantee that different threads won't modify the same memory location, there's no problem.
Yes, for most implementations of vector, this should be ok to do. That said, this will have very poor performance on most systems, unless you have a very large number of elements and you are accessing elements that are far apart from each other so that they don't live on the same cache line... otherwise, on many systems, the two threads will invalidate each other's caches back-and-forth (if you are frequently reading/writing to those elements), leading to lots of cache misses in both threads.
Since C++11:
Different elements in the same container can be modified concurrently
by different threads, except for the elements of std::vector< bool>
(for example, a vector of std::future objects can be receiving values
from multiple threads).
cppreference discusses the thread safety of containers here in good detail.
Link was found in a Quora post.
The fact that "vector is not thread-safe" doesn't mean anything.
There's no problem with doing this.
Also you don't have to allocate your vector on heap (as one of the answers suggested). You just have to ensure that the lifetime of your vector covers the lifetime of your threads (more precisely - where those threads access the vector).
And, of course, since you want your both threads to work on the same vector - they must receive it from somewhere by pointer/reference rather than by value.
There's also absolutely no problem to access the same element of the array from within different threads. You should know however that your thread is not the only one that accesses it, and treat it respectively.
In simple words - there's no problem to access an array from within different threads.
Accessing the same element from different thread is like accessing a single variable from different thread - same precautions/consequences.
The only situation you have to worry about is when new elements are added, which is impossible in your case.
There is no reason why this cannot be done. But, as soon as you start mixing accesses (both threads accessing the same element) it becomes far more challenging.
vector is not thread safe. You need to guard the vector between threads. In your case it depends on vector implementation. If the vector internal data is accessed\modified from different threads, it purely depends on vector impl.
With arrays it can be done for sure (the threads do not access the same memory area); but as already noted, if you use the std::vector class, the result may depend on how it is implemented. Indeed I don't see how the implementation of [] on the vector class can be thread unsafe (provided the threads try to access different "indexes"), but it could be.
The solution is: stick to the use of an array, or control the access to the vector using a semaphore or similar.
What you describe is quite possible, and should word just fine.
Note, however, that the threads will need to work on a std::vector*, i.e. a pointer to the original vector---and you probably should allocate the vector on the heap, rather than the stack. If you pass the vector directly, the copy constructor will be invoked and create a separate copy of the data on each thread.
There are also lots of more subtle ways to get this wrong, as always with multithreaded programming. But in principle what you described will work well.
This should be fine, but you would end up with poor performance due to false sharing where each thread can potentially invalidate each other's cache line