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;
}