Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling mutual exclusion in C++11

I have a class representing a finite-state machine, which should run in a forever loop and check it's current state. In each state machine will set it's next state and either fall into idle state or do some work. I would like to allow another thread to change state of machine while it's working. This will cause a race condition as expected. So I add a mutual exclusion lock/unlock wrapping loop of machine and the public method that allows other threads to change current state of machine.

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

Implementation:

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

And the move method that allows other threads to change current state:

void Robot::move()
{
    mutal_state.lock();
    previousState = currentState; // Booommm
    currentState = nextState;
    mutal_state.unlock();
}

I can't manage to find what I'm doing wrong! Program crashes in first line of the move() function. On the other hand, the GDB is not working with C++11 and tracing code is not possible...

UPDATE:

Playing around code, I can see that problem is in move function. When the program tries to lock code piece inside move(), crashes. For example if move is like this:

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

Output is:

s1
I'm waiting
I'm waiting
MOVE IS CALLED1
The program has unexpectedly finished.

But when move is a simple function, not doing anything:

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 runs concurrently.

like image 378
sorush-r Avatar asked Mar 09 '12 19:03

sorush-r


People also ask

How do you implement mutual exclusion?

It must implement mutual exclusion: only one process can be in the critical section at a time. It must be free of deadlocks: if processes are trying to enter the critical section, one of them must eventually be able to do so successfully, provided no process stays in the critical section permanently.

What is mutual exclusion explain?

In computer programming, a mutex (mutual exclusion object) is a program object that is created so that multiple program thread can take turns sharing the same resource, such as access to a file.

What are mutual exclusion What are the four conditions of mutual exclusion?

No two processes may at the same moment inside their critical sections. No assumptions are made about relative speeds of processes or number of CPUs. No process should outside its critical section should block other processes. No process should wait arbitrary long to enter its critical section.

How mutual exclusion helps in software support explain?

Mutual exclusion is a property of process synchronization which states that “no two processes can exist in the critical section at any given point of time”. The term was first coined by Dijkstra.


1 Answers

My suggestions:

1) if you have no debugger, how can you be so sure it is the first line of move that crashes? It is always with questioning any assumptions you have made about the code, unless you have hard evidence to back it up.

2) I would look at whatever interesting code is in state s3, as this is what the first call to move will perform. Up to that point the code in s3 has not been run. Either that or remove all code bar what is in the posted example, to rule this out.

3) The compiler may make copies of the variables in registers, you should declare all the states as volatile so it knows not to optimise in this way.

like image 129
Matt T Avatar answered Sep 17 '22 12:09

Matt T