std::condition_variable wymaga do działania muteksów i std::unique_lock (ze względu na efektywność). Pozwala to na większą elastyczność, gdyż muteks może zostać zablokowany i odblokowany w dowolnym momencie (std::lock_guard wykorzystuje RAII). Klasa posiada dwa rodzaje metod: wait_* (wait, waif_for, wait_until) oraz notify_* (notify_one, notify_all). Te pierwsze blokują działanie wątku do czasu, aż zostanie spełniony warunek który został przekazany do wait_*. Może to być lambda, punkt w czasie lub odcinek czasu. Natomiast notify_* zajmuje się wybudzaniem wątków.
Ciekawostka, o której dowiedziałem się z cppreference. Przed wołaniem notify_*, należy ręczenie zawołać unlock na obiekcie std::unique_lock (choć destruktor tego obiektu i tak by to wykonał). W ten sposób unikamy sytuacji, w której wybudzamy wątek, tylko po to by ponownie go uśpić, ponieważ warunek nie został jeszcze osiągnięty.
- http://en.cppreference.com/w/cpp/thread/condition_variable
- http://en.cppreference.com/w/cpp/thread/unique_lock
#include <condition_variable>
#include <thread>
#include <mutex>
#include <list>
#include <string>
#include <iostream>
using namespace std;
std::mutex m;
std::condition_variable cv;
std::list<string> train;
void dig_coal() {
int resource = 4;
while(resource >= 0) {
std::unique_lock<std::mutex> l{m};
cv.wait_for(l, std::chrono::milliseconds{400});
if (resource > 0) train.push_back("coal");
else train.push_back("empty");
resource -= 1;
std::cout << "Added trolley, train length: " << train.size() << std::endl;
l.unlock();
cv.notify_one();
}
std::cout << "No more coal to mining." << endl;
}
void burn_coal() {
while(true) {
std::unique_lock<std::mutex> l{m};
cv.wait(l, []{ return not train.empty(); });
const string trolley = train.front();
train.pop_front();
std::cout << "Coal burn, train length: " << train.size() << std::endl;
l.unlock();
cv.notify_one();
if(trolley == "empty") break;
std::this_thread::sleep_for(std::chrono::milliseconds{600});
}
std::cout << "All coal burn." << endl;
}
int main() {
std::thread miner{dig_coal};
std::thread power_station{burn_coal};
cv.notify_one();
miner.join();
power_station.join();
return 0;
}
Wynik:Added trolley, train length: 1 Coal burn, train length: 0 Added trolley, train length: 1 Added trolley, train length: 2 Coal burn, train length: 1 Added trolley, train length: 2 Added trolley, train length: 3 No more coal to mining. Coal burn, train length: 2 Coal burn, train length: 1 Coal burn, train length: 0 All coal burn.
Brak komentarzy:
Prześlij komentarz