-
Always use
wait()
with a predicate! - Remember about spurious wake-ups and lost notifications
-
Remember about a fight for locking a mutex when you use
notify_all()
-
You can't choose which thread should wake up when you use
notify_one()
// assume all necessary includes are here
int main() {
std::mutex m;
std::condition_variable cv;
std::vector<int> v;
std::vector<std::thread> producers;
std::vector<std::thread> consumers;
auto consume = [&] {
std::unique_lock<std::mutex> ul(m);
cv.wait(ul);
std::cout << v.back();
v.pop_back();
};
for (int i = 0; i < 10; i++) consumers.emplace_back(consume);
auto produce = [&](int i) {
{
std::lock_guard<std::mutex> lg(m);
v.push_back(i);
}
cv.notify_all();
};
for (int i = 0; i < 10; i++) producers.emplace_back(produce, i);
for (auto && p : producers) p.join();
for (auto && c : consumers) c.join();
}
- there may be an Undefined Behavior in this code
-
the output is guaranteed to always be
0123456789
-
v
is always an empty vector at the end of this program - if some producers threads started before some consumers, we could have a deadlock because of lost notifications
-
this code can be improved by providing a predicate to
wait()
to disallow getting elements when the vector is empty -
a change from
notify_all()
tonotify_one()
+wait()
with predicate will guarantee that each consumer thread will receive a different number
Note: 1, 4, 5, 6
- Ping-pong
- difficult version - homework/ping_pong.cpp
- easier version - homework/ping_pong_easier.cpp
- Thread A prints "ping" and the consecutive number
- Thread B prints "pong" and the consecutive number
- Ping always starts. Pong always ends.
- Threads must work in turns. There may not be 2 consecutive pings or pongs. The program cannot end with a ping without a respective pong.
- The program must be terminated either after the given number of repetitions or after the time limit, whichever occurs first. The reason for termination should be displayed on the screen.
-
Program parameters:
- number of repetitions
- time limit (in seconds)
$> g++ 03_ping_pong.cpp -lpthread
-std=c++17 -fsanitize=thread
$> ./a.out 1 10
ping 0
pong 0
Ping reached repetitions limit
Pong reached repetitions limit
$> ./a.out 12 1
ping 0
pong 0
ping 1
pong 1
ping 2
pong 2
Timeout
If you got stuck:
-
You need a mutex and a condition variable in your
PingPong
class -
Wait for a condition variable with
wait_for()
instop()
function - Check the number of repetitions in ping and pong threads
-
Use an additional
std::atomic
variable which will tell all threads to end, when the required conditions are met -
Ping and pong threads should be using
wait()
to check if it's their turn to work. Use an additional variable that will be used in the predicate passed towait()
- The pong thread should end the program after reaching the repetition limit
https://github.com/coders-school/condition-variable
- Download a PDF
- Browse presentation content
- Find code examples
- Do the homework!