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