in my example thread 1 and 2 write to the same shared resource x.
and the main thread will read the value.
I want to have the result 24 i.e. thread2 then thread1.
how can I control that ? I tried to define thread 2 before 1 and print the result after join the two threads and the result was 24 but this result is not guaranteed since the threads work in parallel
int x = 10;
void mainThread1(){
x *= 2;
}
void mainThread2(){
x = 2;
}
int main() {
std::thread th1(mainThread1);
std::thread th2(mainThread2);
std::cout << x << std::endl; // random print 20 or 22
th1.join();
th2.join();
}
CodePudding user response:
Presumably you are looking for something other than the trivial answer here: join the first thread before starting the second one. You are showing a simplified example to illustrate a more general situation.
this result is not guaranteed since the threads work in parallel
This is correct. Issues related to relative sequences of operations between multiple threads, and when the effects of one execution thread are "visible" in another execution thread fall into a rather broad, complicated, and extensive C domain called "synchronization".
Inter-thread synchronization employs mutexes, condition variables, and atomics. Just like every other large C topic it is impractical to describe everything that needs to be described about synchronization in a brief answer on Stackoverflow, here. That would take pages. Therefore, I'll just provide a capsule summary of how this simple use case would handle synchronization, and refer you for all further gory details to your favorite C textbook or reference material, for more information. But the basic outline of how to do this here is:
- Define a mutex, a condition variable, and a
boolflag, in addition tox. - The first execution thread locks the mutex, updates
x, sets theboolflag, and notifies the condition variable, then releases the mutex. - The second execution thread locks the mutex, then
wait_forthe condition variable, with the condition beingflag == true. - The second execution thread updates
x, and releases the mutex.
This is the classical solution that guarantees the order of execution, between the two execution threads, that you are looking for. The above answers how to guarantee that the results of
thread2 then thread1
are produced in the shown code.
CodePudding user response:
You could use a global condition_variable so that:
- The thread to be executed in second place waits for it.
- The thread to be executed in first place does its job and sets it.
Notice threads can be waken up from a wait on a condition variable due to spurious wakeups so you should provide an extra mechanism, e.g. a bool, to tell a notify actually happened.
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int x{10};
bool ready{false};
std::mutex m{};
std::condition_variable cv{};
void mainThread1() {
std::unique_lock<std::mutex> lk{m};
cv.wait(lk, []{ return ready; });
x *= 2;
}
void mainThread2() {
x = 2;
ready = true;
cv.notify_one();
}
int main() {
std::thread th1(mainThread1);
std::thread th2(mainThread2);
th1.join();
th2.join();
std::cout << x << "\n"; // prints 24
}
