Can I lock multiple variables simultaneously? - c++

I'm asking a question about multithreading.
Say I have two global vectors,
std::vector<MyClass1*> vec1
and
std::vector<MyClass2*> vec2.
In addition, I have a total number of 4 threads which have access to vec1 and vec2. Can I write code as follows ?
void thread_func()
// this is the function that will be executed by a thread
{
MyClass1* myObj1 = someFunction1();
MyClass2* myObj2 = someFunction2();
// I want to push back vec1, then push back vec2 in an atomic way
pthread_mutex_lock(mutex);
vec1.push_back(myObj1);
vec2.push_back(myObj2);
pthread_mutex_unlock(mutex);
}
for(int i=0; i<4; i++)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_func, NULL);
}
What I want to do is that, I want to perform push_back on vec1 followed by push_back on vec2.
I'm a newbie and I have a feeling that one can only lock on one variable with a mutex. In other words, one can only put either vec1.push_back(myObj1) or vec2.push_back(myObj2) in between pthread_mutex_lock(mutex) and pthread_mutex_unlock(mutex).
I don't know if my code above is correct or not. Can someone correct me if I'm wrong?

Your code is correct. The mutex is the thing being locked, not the variable(s). You lock the mutex to protect a piece of code from being executed by more than one thread, most commonly this is to protect data but in general it's really guarding a section of code.

Yes, you can write like this but there are a few techniques you should definitely consider:
Scoped lock pattern for exception-safety and better robustness in general.
This is nicely explained in this answer
Avoid globals to let optimizer work smarter for you. Try to group data into logical classes and implement locking inside it's methods. Smaller scope of variables also gives you better extensibility.

Related

How to avoid destroying and recreating threads inside loop?

I have a loop with that creates and uses two threads. The threads always do the same thing and I'm wondering how they can be reused instead of created and destroyed each iteration? Some other operations are do inside the loop that affect the data the threads process. Here is a simplified example:
const int args1 = foo1();
const int args2 = foo2();
vector<string> myVec = populateVector();
int a = 1;
while(int i = 0; i < 100; i++)
{
auto func = [&](const vector<string> vec){
//do stuff involving variable a
foo3(myVec[a]);
}
thread t1(func, args1);
thread t2(func, args2);
t1.join();
t2.join();
a = 2 * a;
}
Is there a way to have t1 and t2 restart? Is there a design pattern I should look into? I ask because adding threads made the program slightly slower when I thought it would be faster.
You can use std::async as suggested in the comments.
What you're also trying to do is a very common usage for a Threadpool. I simple header only implementation of which I commonly utilize is here
To use this library, create the pool outside of the loop with a number of threads set during construction. Then enqueue a function in which a thread will go off and execute. With this library, you'll be getting a std::future (much like the std::async steps) and this is what you'd wait on in your loop.
Generically, you'd want to make access to any data thread-safe with mutexs (or other means, there are a lot of ways to do this) but under very specific situations, you'll not need to.
In this case,
so long as the vector isn't being increased in size (doesn't need to reallocate)
Only reading items or only modifying each item at a time in its own thread
the you wouldn't need to worry about synchronization.
Though its just good habit to do the sync anyways... When other people eventually modify the code, they're not going to know your rules and will cause issues.

C++ Threading using 2 Containers

I have the following problem. I use a vector that gets filled up with values from a temperature sensor. This function runs in one thread. Then I have another thread responsible for publishing all the values into a data base which runs once every second. Now the publishing thread will lock the vector using a mutex, so the function that fills it with values will get blocked. However, while the thread that publishes the values is using the vector I want to use another vector to save the temperature values so that I don't lose any values while the data is getting published. How do I get around this problem? I thought about using a pointer that points to the containers and then switching it to the other container once it gets locked to keep saving values, but I dont quite know how.
I tried to add a minimal reproducable example, I hope it kind of explains my situation.
void publish(std::vector<temperature> &inputVector)
{
//this function would publish the values into a database
//via mqtt and also runs in a thread.
}
int main()
{
std::vector<temperature> testVector;
std::vector<temperature> testVector2;
while(1)
{
//I am repeatedly saving values into the vector.
//I want to do this in a thread but if the vector locked by a mutex
//i want to switch over to the other vector
testVector.push_back(testSensor.getValue());
}
}
Assuming you are using std::mutex, you can use mutex::try_lock on the producer side. Something like this:
while(1)
{
if (myMutex.try_lock()) {
// locking succeeded - move all queued values and push the new value
std::move(testVector2.begin(), testVector2.end(), std::back_inserter(testVector));
testVector2.clear();
testVector.push_back(testSensor.getValue());
myMutex.unlock();
} else {
// locking failed - queue the value
testVector2.push_back(testSensor.getValue());
}
}
Of course publish() needs to lock the mutex, too.
void publish(std::vector<temperature> &inputVector)
{
std::lock_guard<std::mutex> lock(myMutex);
//this function would publish the values into a database
//via mqtt and also runs in a thread.
}
This seems like the perfect opportunity for an additional (shared) buffer or queue, that's protected by the lock.
main would be essentially as it is now, pushing your new values into the shared buffer.
The other thread would, when it can, lock that buffer and take the new values from it. This should be very fast.
Then, it does not need to lock the shared buffer while doing its database things (which take longer), as it's only working on its own vector during that procedure.
Here's some pseudo-code:
std::mutex pendingTempsMutex;
std::vector<temperature> pendingTemps;
void thread2()
{
std::vector<temperature> temps;
while (1)
{
// Get new temps if we have any
{
std::scoped_lock l(pendingTempsMutex);
temps.swap(pendingTemps);
}
if (!temps.empty())
publish(temps);
}
}
void thread1()
{
while (1)
{
std::scoped_lock l(pendingTempsMutex);
pendingTemps.push_back(testSensor.getValue());
/*
Or, if getValue() blocks:
temperature newValue = testSensor.getValue();
std::scoped_lock l(pendingTempsMutex);
pendingTemps.push_back(newValue);
*/
}
}
Usually you'd use a std::queue for pendingTemps though. I don't think it really matters in this example, because you're always consuming everything in thread 2, but it's more conventional and can be more efficient in some scenarios. It can't lose you much as it's backed by a std::deque. But you can measure/test to see what's best for you.
This solution is pretty much what you already proposed/explored in the question, except that the producer shouldn't be in charge of managing the second vector.
You can improve it by having thread2 wait to be "informed" that there are new values, with a condition variable, otherwise you're going to be doing a lot of busy-waiting. I leave that as an exercise to the reader ;) There should be an example and discussion in your multi-threaded programming book.

C++ multithreading application crashes

I'm programming a simple 3D rendering engine just to get more familliar with C++. Today I had my first steps with multithreading and already have a problem I cannot wrap my head around. When the application starts it generates a small, minecraft-like terrain consisting of cubes. They're generated withhin the main thread.
Now when I want to generate more chunks
void VoxelWorld::generateChunk(glm::vec2 chunkPosition) {
Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader = m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
}
void VoxelWorld::generateChunkThreaded(glm::vec2 chunkPosition) {
std::thread chunkThread(&VoxelWorld::generateChunk, this, chunkPosition);
chunkThread.detach();
}
void VoxelWorld::draw() {
for(glm::vec2& vec : m_loadedChunks){
Transformation* transformation = new Transformation();
transformation->getPosition().setPosition(glm::vec3(CHUNK_WIDTH*vec.x, 0, CHUNK_WIDTH*vec.y));
m_chunks[vec.x][vec.y]->getRenderObject()->draw(transformation);
delete(transformation); //TODO: Find a better way
}
}
I have my member function (everything is non-static) generateChunk() which generates a Chunk and stores it in the VoxelWorld class. I have a 2D std::map<..> m_chunks which stores every chunk and a std::vector<glm::vec2> m_loadedChunks which stores the positions of the generated chunks.
Calling generateChunk() works fine as expected. But when I try generateChunkThreaded() the application crashes! I tried commenting out the last line of generateChunk(), then it does not crash. Thats what confuses me so much! m_loadedChunks ist just a regular std::vector. I tried making it public, with no effect. Is there anything obvious I miss?
You are accessing m_loadedChunks from several threads without synchronizing it.
You need to lock the usage of shared usages. So few tips here.
Declare a mutex as a member of the class
std::mutex mtx; // mutex for critical section
Use it to lock via a critical section each time you want to access the elements
std::lock_guard lock(mtx);
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
Hope that helps
When you have many threads access shared resources, you either have those resources available as read-only, atomic, or guarded with a mutex lock.
So, for your m_loadedChunks member variable, you would want to have it wrapped in a lock. For example:
class VoxelWorld
{
// your class members and more ...
private:
std::mutex m_loadedChunksMutex;
}
void VoxelWorld::generateChunk(glm::vec2 chunkPosition)
{
Chunk* generatedChunk = m_worldGenerator->generateChunk(chunkPosition);
generatedChunk->shader = m_chunkShader;
generatedChunk->generateRenderObject();
m_chunks[chunkPosition.x][chunkPosition.y] = generatedChunk;
{
auto&& scopedLock = std::lock_guard< std::mutex >(m_loadedChunksMutex);
(void)scopedLock;
m_loadedChunks.push_back(glm::vec2(chunkPosition.x, chunkPosition.y));
}
}
The scopedLock will automatically wait for a lock and when the code goes out of scope, the lock will be released.
Now note, that I have a mutex for m_loadedChunks and not a generic mutex covering all variables that may be accessed by threads. This is actually a good practice introduced by Herb Sutter in his "Effective Concurrency" courses and on his talks at cppcon.
So, for whatever shared variables you have, use the above example as one means to solve race issues.

Best way to copy array(float) to local array(float)

Okay so I have a structure which continuously updates in a seperate thread.
Now I need some of these variables locally somewhere without them changing in between.
I first did this to get them locally which obviously isn't the best method but it worked.
float MyFloatArray[3];
MyFloatArray[0] = otherThread()->floatArray[0];
MyFloatArray[1] = otherThread()->floatArray[1];
MyFloatArray[2] = otherThread()->floatArray[2];
Now I was wondering if there is a better way to do this.
I already tried the following:
float MyFloatArray = otherThread()->floatArray;
float* MyFloatArray = otherThread()->floatArray; //Works but updates the otherThread array(Obviously) but that shouldn't happen
Since I have a decently big project it'll be a lot of work to update all these to std::array<float,3>
Is there any alternative? Otherwise I will update all my float arrays to std::array<float,3> since it's a lot cleaner if there is no alternative.
You could simply call std::copy, making sure the copy is guarded by a synchronisation mechanism such as a mutex. For example:
std::mutex m; // otherThread() must lock this mutex when modifying array
{
std::lock_guard<std::mutex> lock(m);
std::copy(otherThread()->floatArray, otherThread()->floatArray + 3, MyLoatArray);
}
or use a copyable type, such as std::array<float, 3> and use assignment. Again, this has to be protected with a synchronisation mechanism:
std::mutex m; // otherThread() must lock this mutex when modifying array
{
std::lock_guard<std::mutex> lock(m);
MyFloatArray = otherThread()->floatArray;
}
What you need is an atomic copy operation. Unfortunately, that doesn't exist for entire structures, so you will have to use a mutex to lock accesses to the structure for the duration of your copy operation (and, in the other thread, for the duration of modifications to the structure).
Then you can either stick with your element-wise assignment, or switch to std::copy; it doesn't really matter. Fundamentally the latter is still going to compile down to an element-wise assignment. No matter what syntax you use, your CPU still has to copy a series of bytes and it cannot do that in a single, atomic operation. But as long as your reads and writes to the structure are protected by a mutex, you'll be fine.

Simplest Mutex ever. Does this example work? Is it thread-safe?

I would like to ask about the simplest Mutex approach ever for multi-threading. Is the following code thread-safe (quick-n-dirty)?
class myclass
{
bool locked;
vector<double> vals;
myclass();
void add(double val);
};
void myclass::add(double val)
{
if(!locked)
{
this->locked = 1;
this->vals.push_back(val);
this->locked = 0;
}
else
{
this->add(val);
}
}
int main()
{
myclass cls;
//start parallelism
cls.add(static_cast<double>(rand()));
}
Does this work? Is it thread-safe? I'm just trying to understand how the simplest mutex can be written.
If you have any advice about my example, would be nice.
Thank you.
Thanks for saying that it doesn't work. Can you please suggest a fix which is compiler independent?
Is it thread-safe?
Certainly not. If a thread is preempted between checking and setting the lock, then a second thread could acquire that lock; if control then returns to the first thread, then both will acquire it. (And of course, on a modern processor, two or more cores could be executing the same instructions simultaneously for even more hilarity.)
At the very least, you need an atomic test-and-set operation to implement a lock like this. The C++11 library provides such a thing:
std::atomic_flag locked;
if (!locked.test_and_set()) {
vals.push_back(val);
locked.clear();
} else {
// I don't know exactly what to do here;
// but recursively calling add() is a very bad idea.
}
or better yet:
std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
vals.push_back(val);
If you have an older implementation, then you'll have to rely on whatever extensions/libraries are available to you, as there was nothing helpful in the language or standard library back then.
No, this is not thread safe. There's a race between
if(!locked)
and
this->locked = 1;
If there is a context switch between these two statements, your lock mechanism falls apart. You need an atomic test and set instruction, or simply use an existing mutex.
This code doesn't provide an atomic modification of vals vector. Consider the following scenario:
//<<< Suppose it's 0
if(!locked)
{ //<<< Thread 0 passes the check
//<<< Context Switch - and Thread 1 is also there because locked is 0
this->locked = 1;
//<<< Now it's possible for one thread to be scheduled when another one is in
//<<< the middle of modification of the vector
this->vals.push_back(val);
this->locked = 0;
}
Does this work? Is it thread-safe?
No. It will fail at times.
Your mutex will only work if other threads never do anything between the execution of these two lines:
if(!locked)
{
this->locked = 1;
...and you have not ensured that.
To learn about the how of mutex writing, see this SO post.
No, that is not thread safe.
Consider two threads running myclass::add at more-or-less the same time. Also, imagine that the value of .locked is false.
The first thread executes up to and including this line:
if(!locked)
{
Now imagine that the system switches context to the second thread. It also executes up to the same line.
Now we have two different threads, both believing that they have exclusive access, and both inside the !locked condition of the if.
They will both call vals.push_back() at more-or-less the same time.
Boom.
Others have already shown how your mutex can fail, so I won't rehash their points. I will only add one thing: The simplest mutex implementation is a lot more complicated than your code.
If you're interested in the nitty gritty (or even if you are not - this is stuff every software developer should know) you should look at Leslie Lamport's Bakery Algorithm and go from there.
You cannot implement it in C++. You have to use LOCK CMPXCHG. Here is my answer from here:
; BL is the mutex id
; shared_val, a memory address
CMP [shared_val],BL ; Perhaps it is locked to us anyway
JZ .OutLoop2
.Loop1:
CMP [shared_val],0xFF ; Free
JZ .OutLoop1 ; Yes
pause ; equal to rep nop.
JMP .Loop1 ; Else, retry
.OutLoop1:
; Lock is free, grab it
MOV AL,0xFF
LOCK CMPXCHG [shared_val],BL
JNZ .Loop1 ; Write failed
.OutLoop2: ; Lock Acquired