簡體   English   中英

C++ 11 與 std::atomic 同步

[英]Synchronisation in C++ 11 with std::atomic

我有以下代碼在英特爾處理器上運行良好,但在 ARM 處理器上產生奇怪的數據。
我懷疑這是一個同步問題。

基本上我有一個定期調用setLiveData(...) getLiveData(...)消費者線程。

.h 文件

class DataHandler{
public:
...
private:

    LiveDataValue lastValues_;
    bool lastValuesValid;
};

.cpp 文件

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

僅通過閱讀代碼,我認為我需要確保setLiveData是原子的,因為消費者線程無法調用getLiveData(...)而生產者線程位於setLiveData(...)中間

我找到了這個答案並嘗試用它來修復代碼:

.h 文件

class DataHandler{
public:
...
private:

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

.cpp 文件

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

我的問題是我從不退出讀取器線程調用的 getLiveData 中的 while 循環。 這是為什么?

編輯:LiveDataValue 是一個復雜的聯合類型定義,這里不詳述。

您的問題是您的代碼沒有同步,而不是您的循環沒有結束。

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

您可以檢查最后一個值是否有效、是否為真,以及在您分配時它們是否有效。 任何有效性檢查都不會在之后立即生效,它只是告訴您在過去的某個時間點它們有效。

template<class T>
struct mutex_guarded {
  template<class F>
  void read( F&& f ) const {
    auto l = std::unique_lock<std::mutex>(m);
    f(t);
  }
  template<class F>
  void write( F&& f ) {
    auto l = std::unique_lock<std::mutex>(m);
    f(t);
  }
private:
  mutable std::mutex m;
  T t;
};

這是一個簡單的包裝器,用於序列化對任意類型的某些數據的訪問。

class DataHandler{
public:
...
private:

  struct Data {
    LiveDataHolder lastValues_;
    bool lastValuesValid_ = false;
  };
  mutex_guarded<Data> data_;
};

然后

bool DataHandler::getLiveData(LiveDataValue *val) const
{
  bool bRet = false;
  data_.read([&](Data const& data_){
    bRet = data_.lastValuesValid_;
    if (!bRet) return;
    *val = data_.lastValues;
  });
  return bRet;
}

void DataHandler::setLiveData(LiveDataValue val)
{
  data_.write([&](Data & data_){
    data_.lastValues = std::move(val);
    data_.lastValuesValid = true;
  });
}

將自動修改有效和值字段。

.read(lambda).write(lambda)中所做的一切都是在通過鎖定互斥鎖保護的同時完成的。 lambda 傳遞一個T const&或一個T&取決於它是讀取還是寫入操作,並且沒有其他方法可以訪問受保護的數據。

(擴展它以支持讀/寫鎖相對容易,但保持簡單是一個很好的經驗法則,所以我只是用互斥鎖寫了它)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM