lundi 1 mars 2021

Synchronisation in C++ 11 with std::atomic

I have the following code that runs fine on Intel processors but produces weird data on ARM processors.
I suspect that this is a synchronisation problem.

Basically I have a producer thread calling setLiveData(...) periodically and a consumer thread calling getLiveData(...) periodically as well.

.h file

class DataHandler{
public:
...
private:

    LiveDataValue lastValues_;
    bool lastValuesValid;
};

.cpp file

bool DataHandler::getLiveData(LiveDataValue *val)
{
    if(this->lastValuesValid){
        *val = this->lastValues_;
        return true;
    }else
        return false;
}

void DataHandler::setLiveData(LiveDataValue val)
{
    this->lastValuesValid = false;
    this->lastValues = val;
    this->lastValuesValid = true;
}

Just by reading the code, I think that I need to make sure that setLiveData is atomic in the sense that a consumer thread can't call getLiveData(...) while a producer thread is in the middle of setLiveData(...)

I've found this answer and tried to used it fixing the code:

.h file

class DataHandler{
public:
...
private:

    LiveDataValue lastValues_;
    std::atomic<bool> lastValuesValid;
};

.cpp file

bool DataHandler::getLiveData(LiveDataValue *val)
{
   while (!this->lastValuesValid.load(std::memory_order_acquire))
   {
       std::this_thread::yield();
   }

    if(this->lastValuesValid){
        *val = this->lastValues_;
        return true;
    }else
        return false;
}

void DataHandler::setLiveData(LiveDataValue val)
{
    this->lastValuesValid_.store(false, std::memory_order_release);
    this->lastValues = val;
    this->lastValuesValid_.store(true, std::memory_order_release);
}

My problem is that I never exit the while loop in getLiveData called by the reader thread. Why is that?

EDIT : LiveDataValue is a complex union typedef, not detailed here.

Aucun commentaire:

Enregistrer un commentaire