Mam klasę reprezentującą maszynę o stanie skończonym, która powinna działać w pętli wiecznej i sprawdzać jej bieżący stan. W każdym automatie stanowym ustawi go na następny stan i albo zapadnie w stan idle
albo wykona jakąś pracę. Chciałbym umożliwić innym wątkom zmianę stanu maszyny podczas jej pracy. Spowoduje to oczekiwany stan wyścigu. Dodaję więc wspólną blokadę wyłączania/odblokowywania pętli maszyny oraz metodę publiczną, która pozwala innym wątkom zmienić bieżący stan maszyny.Obsługa wzajemnego wykluczania w C++ 11
class Robot
{
public:
enum StateType {s1,s2,s3,idle,finish};
void run();
void move();
private:
StateType currentState;
StateType nextState;
StateType previousState;
std::mutex mutal_state;
};
Realizacja:
void Robot::run()
{
this->currentState = s1;
while(true)
{
mutal_state.lock();
switch(currentState)
{
case s1:
// do some useful stuff here...
currentState = idle;
nextState = s3;
break;
case s2:
// do some other useful stuff here...
currentState = idle;
nextState = finish;
break;
case s3:
// again, do some useful things...
currentState = idle;
nextState = s2;
break;
case idle:
// busy waiting...
std::cout << "I'm waiting" << std::endl;
break;
case finish:
std::cout << "Bye" << std::endl;
mutal_state.unlock();
return;
}
mutal_state.unlock();
}
}
A metoda, która pozwala przenieść inne wątki zmienić aktualny stan:
void Robot::move()
{
mutal_state.lock();
previousState = currentState; // Booommm
currentState = nextState;
mutal_state.unlock();
}
nie uda się znaleźć to, co robię źle! Program ulega awarii w pierwszej linii funkcji move()
. Z drugiej strony, GDB nie działa z C++ 11 i kod śledzenia nie jest możliwe ...
UPDATE:
Odtwarzanie wokół kodu, widzę, że problem jest w funkcji ruchu. Kiedy program próbuje zablokować fragment kodu wewnątrz move()
, ulega awarii. Na przykład, jeśli ruch jest tak:
void Robot::move()
{
std::cout << "MOVE IS CALLED" << std::endl;
mutal_state.lock();
//previousState = currentState;
//std::cout << "MOVING" << std::endl;
//currentState = nextState;
mutal_state.unlock();
}
wyjściowa wynosi:
s1
I'm waiting
I'm waiting
MOVE IS CALLED1
The program has unexpectedly finished.
Ale kiedy move
to prosta funkcja, nie robi nic:
void Robot::move()
{
std::cout << "MOVE IS CALLED" << std::endl;
//mutal_state.lock();
//previousState = currentState;
//std::cout << "MOVING" << std::endl;
//currentState = nextState;
//mutal_state.unlock();
}
Program biegnie równolegle.
Czy próbowałeś debugowania za pomocą instrukcji drukowania? – FrustratedWithFormsDesigner
@ FrustratedWithFormsDesigner: Tak. Wiem, że "eksplozja" ma miejsce tylko wtedy, gdy jakiś wątek próbuje wywołać "ruch". –
Jakiej wersji kompilatora używasz? – ildjarn