2016-01-23 110 views
0

我需要在一些外部函數中通過私有互斥鎖來鎖定對象。做這個的最好方式是什麼?
我想是這樣的通過私有互斥鎖鎖定對象的最佳方法是什麼?

#include <thread> 
#include <mutex> 

class Test 
{ 
public: 
    std::lock_guard<std::mutex> lockGuard() 
     { 
      return std::lock_guard<std::mutex>(mutex); 
     } 

private: 
    std::mutex mutex; 
}; 

int main() 
{ 
    Test test; 
    std::lock_guard<std::mutex> lock = test.lockGuard(); 
    //... 
} 

lock_guard拷貝構造器中被刪除。我該如何做這樣的事情?

+1

使用'unique_lock'代替? –

+0

如果我用'lock_guard'替換'lock_guard',我會得到我需要的嗎? – Ufx

+0

如果對象只是從外部鎖定,而不是從內部鎖定,爲什麼互斥體需要在內部聲明? –

回答

1

std::unique_lock<T>定義了一個移動構造函數,可以隨意使用,但這種方法本身並不是非常成功。 您應該檢查您的鎖定粒度,通常如果您無法提供內部同步並要求用戶在對某個對象執行操作(或需要執行多個操作時)時保持鎖定狀態,則沒有理由將該互斥鎖存儲在目的。

如果我不得不店內對象互斥,我會用一些包裝,讓我做到以下幾點:

locking_wrapper<Test> test; 
test.do_locked([] (Test & instance) { 
    /* The following code is guaranteed not to interleave with 
    * any operations performed on instance from other threads. */ 
    // your code using instance here 
}); 

locking_wrapper<T>將存儲存儲內的對象的實例,並提供一個參考它同時保持對內部互斥鎖的鎖定。依靠編譯器內聯代碼的能力,這種方法不應該超出你想要解決的問題。

上實現locking_wrapper總體思路如下:

template<typename T> 
class locking_wrapper 
{ 
    mutable std::mutex mutex; 
    // the object which requires external synchronization on access 
    T instance; 

public: 
    /* Here we define whatever constructors required to construct the 
    * locking_wrapper (e.g. value-initialize the instance, take an 
    * instance passed by user or something different) */ 
    locking_wrapper() = default; 
    locking_wrapper(const T & instance) : instance{instance} {} 

    // Takes a functor to be performed on instance while maintaining lock 
    template<typename Functor> 
    void do_locked(Functor && f) const { 
     const std::lock_guard<std::mutex> lock{mutex}; 
     f(instance); 
    } 
}; 

您可以調用任何實體傳遞給do_locked,你認爲合適,但是是lambda表達式調用它就像我先前建議將給它最好的機會,而不用任何開銷。

請注意,使用這種方法與引用,可移動對象或其他類型,我還沒有預見將需要對代碼進行一些修改。

+0

什麼是「自我」? – erip

+0

'self'是存儲在'test'裏的'Test'類型的對象。也許這個名字是誤導性的,我應該把它稱爲「實例」或「對象」。 – Hertz

+0

爲什麼你的括號不匹配的任何特定原因? 我會在那裏問一些關於那個lambda魔法的更多解釋。 –

2

改爲使用std::unique_lock<std::mutex>。它是不是可複製,但它可移動的,允許你顯示的模式。

#include <thread> 
#include <mutex> 

class Test 
{ 
public: 
    std::unique_lock<std::mutex> lockGuard() 
     { 
      return std::unique_lock<std::mutex>(mutex); 
     } 

private: 
    std::mutex mutex; 
}; 

int main() 
{ 
    Test test; 
    std::unique_lock<std::mutex> lock = test.lockGuard(); 
    //... 
} 

std::unique_lock<std::mutex>具有加寬API相對於std::lock_guard包括:

  • 移動構造的。
  • 移動可分配。
  • 可交換。
  • 鎖()
  • 解鎖()
  • try_lock()
  • try_lock_for()
  • try_lock_until()
  • 釋放()
  • owns_lock()

在其它單詞,因爲您可以解鎖並從unique_lock移出,因此不能保證對該互斥鎖持有鎖定(您可以檢查它與owns_lock())。相比之下,lock_guard的不變量是它始終保持互斥鎖。