Reputation: 6546
I got addicted to learning concurrency again and tried to solve this problem.
In short, I have a class and 3 functions. I need to sync their calls (need to print FirstSecondThird
).
It will become more clear with the code below:
std::function<void()> printFirst = []() { std::cout << "First"; };
std::function<void()> printSecond = []() { std::cout << "Second"; };
std::function<void()> printThird = []() { std::cout << "Third"; };
class Foo {
std::condition_variable cv;
bool mfirst,msecond;
std::mutex mtx;
public:
Foo() {
mfirst = false;
msecond = false;
}
void first(std::function<void()> printFirst) {
std::unique_lock<std::mutex> l(mtx);
printFirst();
mfirst = true;
}
void second(std::function<void()> printSecond) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this]{return mfirst == true; });
printSecond();
msecond = true;
}
void third(std::function<void()> printThird) {
std::unique_lock<std::mutex> l(mtx);
cv.wait(l, [this] {return (mfirst && msecond) == true; });
printThird();
}
};
int main()
{
Foo t;
std::thread t3((&Foo::third, t, printThird));
std::thread t2((&Foo::second, t, printSecond));
std::thread t1((&Foo::first, t, printFirst));
t3.join();
t2.join();
t1.join();
return 0;
}
And guess what my output is? It prints ThirdSecondFirst
.
How is this possible? Isn't this code prone to DEADLOCK? I mean, when the first thread acquired the mutex in function second
, wouldn't it wait forever because now as mutex is acquired we cannot change variable mfirst
?
Upvotes: 1
Views: 89
Reputation: 1201
You have a very subtle bug.
std::thread t3((&Foo::third, t, printThird));
This line does not do what you expect. It initializes a thread with only one argument, printThird
, instead of initializing with the 3 arguments you specified. That's because you accidentally used a comma expression. As a result, &Foo::third
and t
are just discarded, and the member functions are never even called.
The only functions that are called in your code are printFirst
, printSecond
, and printThird
. Without any synchronization, they may print in arbitrary order. You may even get interleaved output.
std::thread t3{&Foo::third, t, printThird};
Here is the corrected version. The curly braces are for avoiding the compiler treating this as a function declaration because of most vexing parse
As a side note, as mentioned in the comments, you are using condition variables wrong.
Upvotes: 2