W aplikacji występuje zakleszczenie. Proszę je wyeliminować dbając o to, aby rozwiązanie było poprawne (bez wyścigów). Nie modyfikuj funkcji main
.
W funkcji main
występują obiekty ref(x)
. Są to obiekty pomocnicze, które zapobiegają tworzeniu kopii obiektu, więc np.
thread thrd1( ref(p1) );
oznacza, że konstruktor std::thread
nie wykona kopii obiektu p1
.
Nie jest to kluczowe do znalezienia rozwiązania.
Posługujemy się także listą dwukierunkową z biblioteki standardowej, z operacjami push_back
(wstawiania na koniec), pop_front
(usuwanie początkowego elementu), front
(zwraca początkowy element listy).
#include <list> #include <memory> #include <thread> #include <mutex> #include <functional> #include <iostream> using namespace std; const int NUM = 100; class Calc { public: Calc(int idx) : idx_(idx) { out_.push_back(0); out_.push_back(0); } void setPrev(Calc* p) { prev_ = p; } int get() { int ret = -1; lock_guard<mutex> lock(m_); if(!out_.empty() ) { ret = out_.front(); out_.pop_front(); } return ret; } void operator()() { for(int i=0;i<NUM;++i) { lock_guard<mutex> lock(m_); if(prev_) { int x = prev_->get(); std::this_thread::sleep_for( chrono::milliseconds(100)); //symuluje długotrwałe lokalne obliczenia if( x >= 0) { out_.push_back(x + 1); } } } } private: int idx_; Calc* prev_ = nullptr; list<int> out_; mutex m_; }; int main () { Calc p1(1), p2(2), p3(3); p1.setPrev(&p3); p2.setPrev(&p1); p3.setPrev(&p2); thread thrd1( ref(p1) ); thread thrd2( ref(p2) ); thread thrd3( ref(p3) ); thrd1.join(); thrd2.join(); thrd3.join(); cout << "thrd1: " << p1.get() << endl; cout << "thrd2: " << p2.get() << endl; cout << "thrd3: " << p3.get() << endl; return 0; }