COMP6771 Advanced C++ Programming: Week 10 Multithreading - Producer/Consumer Problem
COMP6771 Advanced C++ Programming: Week 10 Multithreading - Producer/Consumer Problem
COMP6771
Advanced C++ Programming
Week 10
Multithreading - Producer/Consumer Problem
2016
www.cse.unsw.edu.au/˜cs6771
1
Recap Condition Variables Futures
.... ...... .....
2
Recap Condition Variables Futures
.... ...... .....
std::mutex
3
Recap Condition Variables Futures
.... ...... .....
std::mutex example
1 #include <iostream>
2 #include <thread>
3 #include <mutex>
4
5 int main() {
6 int i = 1;
7 const long numIterations = 1000000;
8 std::mutex iMutex;
9 std::thread t1([&] {
10 for (int j = 0; j < numIterations; ++j) {
11 iMutex.lock();
12 i++;
13 iMutex.unlock();
14 }
15 });
16 std::thread t2([&] {
17 for (int j = 0; j < numIterations; ++j) {
18 iMutex.lock();
19 i--;
20 iMutex.unlock();
21 }
22 });
23 t1.join();
24 t2.join();
25 std::cout << i << std::endl;
26 }
4
Recap Condition Variables Futures
.... ...... .....
Lock Guards
RAII wrapper class around a mutex.
1 #include <iostream>
2 #include <thread>
3 #include <mutex>
4
5 int main() {
6 int i = 1;
7 const long numIterations = 1000000;
8 std::mutex iMutex;
9 std::thread t1([&] {
10 for (int j = 0; j < numIterations; ++j) {
11 std::lock_guard<std::mutex> guard(iMutex);
12 i++;
13 }
14 });
15 std::thread t2([&] {
16 for (int j = 0; j < numIterations; ++j) {
17 std::lock_guard<std::mutex> guard(iMutex);
18 i--;
19 }
20 });
21 t1.join();
22 t2.join();
23 std::cout << i << std::endl;
24 }
5
Recap Condition Variables Futures
.... ...... .....
Producer-Consumer Problem
6
Recap Condition Variables Futures
.... ...... .....
Producer-Consumer Problem
1 class ManufacturingPlant {
2 public:
3 ManufacturingPlant() : materialsCount{0} {}
4
5 void receiveMaterials(int i);
6 int produceProduct();
7 private:
8 int materialsCount;
9 std::mutex materialsCountMutex;
10 const int CAPACITY = 100;
11 };
7
Recap Condition Variables Futures
.... ...... .....
Producer-Consumer Problem
1 class Truck {
2 public:
3 Truck(ManufacturingPlant& m) : mp{m} {}
4 void deliverMaterials() {
5 mp.receiveMaterials(10);
6 }
7 private:
8 ManufacturingPlant& mp;
9 };
10
11 class Train {
12 public:
13 Train(ManufacturingPlant& m) : mp{m} {}
14 void getProduct() {
15 mp.produceProduct();
16 }
17 private:
18 ManufacturingPlant& mp;
19 };
8
Recap Condition Variables Futures
.... ...... .....
Producer-Consumer Problem
1 void ManufacturingPlant::receiveMaterials(int i) {
2 std::lock_guard<std::mutex> lg(materialsCountMutex);
3 if (materialsCount + i > CAPACITY) {
4 // TODO: wait for capacity!
5 }
6 materialsCount += i;
7 }
8
9 int ManufacturingPlant::produceProduct() {
10 std::lock_guard<std::mutex> lg(materialsCountMutex);
11 if (materialsCount - 10 > 0) {
12 // TODO: wait for materials to arrive
13 }
14 materialsCount -= 10;
15 return 10;
16 }
Problem: how do we release the lock and wait for either capacity
or materials?
9
Recap Condition Variables Futures
.... ...... .....
Condition Variables
Condition variables allow threads to block, release a mutex,
and wait until data is set by another thread or until a time
period has elapsed.
Explicit inter-thread communication.
When we need to check/wait for a condition to be true, we
call wait() on the condition variable.
If we need to signal (communicate) that some data has been
made available we need to notify one() or notify all()
on the condition variable.
Need to add to the class:
1 // used to signal the arrival of materials
2 std::condition_variable hasMaterials;
3 // used to signal the removal of materials
4 std::condition_variable hasCapacity;
10
Recap Condition Variables Futures
.... ...... .....
Futures
12
Recap Condition Variables Futures
.... ...... .....
std::async
13
Recap Condition Variables Futures
.... ...... .....
Example sketch
1 #include <iostream>
2 #include <future>
3 #include <thread>
4 #include <chrono>
5
6 int calculate() {
7 return 123;
8 }
9
10 int main() {
11 std::future<int> fut = std::async(calculate);
12 // note can force to launch a new thread using:
13 // std::future<int> fut = std::async(std::launch::async,calculate);
14
15 bool doOtherWork = true;
16 while (doOtherWork) {
17 // check if the result is available.
18 if (fut.wait_for(std::chrono::seconds(0)) == std::future_status::timeout) {
19 // do other work.. e.g. go to a different factory.
20 } else {
21 // either the result is available or the launch has been deferred
22 doOtherWork = false;
23 }
24 }
25
26 int res = fut.get(); // get the result from the future
27 std::cout << res << std::endl;
28 }
1 try {
2 int res = fut.get(); // get the result from the future
3 std::cout << res << std::endl;
4 } catch (const std::exception& ex) {
5 std::cout << "Exception caught" << std::endl;
6 }
15
Recap Condition Variables Futures
.... ...... .....
Readings
16