簡體   English   中英

c ++ 11原子對象的執行是否也是原子的?

[英]Is the execution of a c++ 11 atomic object also atomic ?

我有一個對象,其所有功能應按順序執行。 我知道可以使用互斥鎖來做到這一點

#include <mutex> 

class myClass {
private:
    std::mutex mtx;
public:
    void exampleMethod();
};

void myClass::exampleMethod() {
    std::unique_lock<std::mutex> lck (mtx); // lock mutex until end of scope

    // do some stuff
}

但是使用此技術時,在exampleMethod中調用其他互斥鎖方法后會發生死鎖。

所以我正在尋找更好的分辨率。 默認的std :: atomic訪問是順序一致的,因此不可能同時讀取對該對象的寫入,但是現在當我訪問對象並調用方法時,整個函數調用是否也是原子的或更多類似的東西

object* obj = atomicObj.load(); // read atomic
obj.doSomething(); // call method from non atomic object;

如果是,有沒有比使用互斥鎖鎖定大多數功能更好的方法了?

停下來想一想何時實際需要鎖定互斥鎖。 如果您有一些在許多其他函數中調用的輔助函數,則它可能不應嘗試鎖定互斥鎖,因為調用者已經擁有了。

如果在某些情況下沒有被另一個成員函數調用,因此確實需要獲取鎖,請提供一個實際執行該操作的包裝器函數。 具有兩個版本的成員函數,公共foo()和私有fooNoLock()並不罕見,其中:

public:
void foo() {
    std::lock_guard<std::mutex> l(mtx);
    fooNoLock();
}

private:
void fooNoLock() {
    // do stuff that operates on some shared resource...
}

根據我的經驗,遞歸互斥是一種代碼味道 ,表明作者並沒有真正意識到使用函數的方式-並非總是錯誤的,但是當我看到一個時,我就感到可疑。

至於原子運算,它們實際上只能應用於較小的算術運算,例如遞增整數或交換2個指針。 這些操作不是自動的原子操作,但是當您使用原子操作時,它們是可以用於這些操作的種類。 您肯定對單個原子對象上的2個獨立操作沒有任何合理的期望。 在兩次操作之間可能發生任何事情。

您可以改用std :: recursive_mutex 這將使已擁有的線程互斥以重新獲取它而不會阻塞。 但是,如果另一個線程嘗試獲取該鎖,它將阻塞。

正如@BoBTFish正確指出的那樣,最好將您的類的公共接口分開,該成員函數獲取非遞歸鎖,然后調用那些非遞歸鎖。 然后,您的代碼必須假定在運行私有方法時始終保持鎖定。

為了安全起見,您可以向每個需要保持鎖的方法添加對std::unique_lock<std::mutex>的引用。

因此,即使您碰巧從另一個調用一個私有方法,也需要確保互斥體在執行之前被鎖定:

class myClass
{
  std::mutex mtx;

//
  void i_exampleMethod(std::unique_lock<std::mutex> &)
  {
     // execute method
  }

public:
  void exampleMethod()
  {
    std::unique_lock<std::mutex> lock(mtx);
    i_exampleMethod(lock);
  }
};

暫無
暫無

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

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