2010-04-02 19 views
1

我有一個使用升壓互斥體和鎖像這樣(只相關部分)的自定義類:爲什麼boost :: recursive_mutex不能按預期工作?

template<class T> class FFTBuf 
{ 
    public: 
     FFTBuf(); 
     [...] 
     void lock(); 
     void unlock(); 
    private: 
     T *_dst; 
     int _siglen; 
     int _processed_sums; 
     int _expected_sums; 
     int _assigned_sources; 
     bool _written; 
     boost::recursive_mutex _mut; 
     boost::unique_lock<boost::recursive_mutex> _lock; 
}; 

template<class T> FFTBuf<T>::FFTBuf() : _dst(NULL), _siglen(0), 
    _expected_sums(1), _processed_sums(0), _assigned_sources(0), 
    _written(false), _lock(_mut, boost::defer_lock_t()) 
{ 
} 

template<class T> void FFTBuf<T>::lock() 
{ 
    std::cerr << "Locking" << std::endl; 
    _lock.lock(); 
    std::cerr << "Locked" << std::endl; 
} 

template<class T> void FFTBuf<T>::unlock() 
{ 
    std::cerr << "Unlocking" << std::endl; 
    _lock.unlock(); 
} 

如果我試圖鎖定不止一次對象更在同一個線程,我得到一個異常( lock_error):

#include "fft_buf.hpp" 

int main(void) { 
    FFTBuf<int> b(256); 
    b.lock(); 
    b.lock(); 
    b.unlock(); 
    b.unlock(); 

    return 0; 
} 

這是輸出:

[email protected] $ ./src/test 
Locking 
Locked 
Locking 
terminate called after throwing an instance of 'boost::lock_error' 
    what(): boost::lock_error 
zsh: abort ./src/test 

這是爲什麼HAP pening?我是否正確理解了一些概念?

回答

2

試試這個:

template<class T> void FFTBuf<T>::lock() 
{ 
    std::cerr << "Locking" << std::endl; 
    _mut.lock(); 
    std::cerr << "Locked" << std::endl; 
} 

template<class T> void FFTBuf<T>::unlock() 
{ 
    std::cerr << "Unlocking" << std::endl; 
    _mut.unlock(); 
} 

您使用unique_lock _lock的同一實例兩次,這是一個問題。 您必須直接使用遞歸互斥鎖的方法lock()和unock(),或者使用兩個不同的unique_lock實例,例如_lock_lock_2;。

更新

我想補充一點,你的類有公共方法lock()unlock()和我在一個真正的程序的角度來看這是一個壞主意。在實際程序中將unique_lock作爲類的成員也常常是一個壞主意。

+0

這有效,但爲什麼? – Kjir 2010-04-02 13:52:27

+0

那麼boost :: unique_lock的用途是什麼?它簡單地使用互斥鎖有什麼優勢?我猜想,RAII, – Kjir 2010-04-02 14:20:34

+2

。 http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization – 2010-04-02 14:22:48

3

鎖定不應該是受保護資源的一部分,而應該是調用者的一部分,因爲您有一個線程調用者。他們必須使用不同的unique_lock。

unique_lock的目的是用RAII鎖定和釋放互斥鎖,所以你不必明確地調用unlock。

當unique_lock在方法體內聲明時,它將屬於調用線程堆棧。

所以更正確的使用方法是:

#include <boost/thread/recursive_mutex.hpp> 
#include <iostream> 

template<class T> 
class FFTBuf 
{ 
public : 
    FFTBuf() 
    { 
    } 

    // this can be called by any thread 
    void exemple() const 
    { 
     boost::recursive_mutex::scoped_lock lock(mut); 
     std::cerr << "Locked" << std::endl; 

     // we are safe here 
     std::cout << "exemple" << std::endl ; 

     std::cerr << "Unlocking (by RAII)" << std::endl; 
    } 

    // this is mutable to allow lock of const FFTBuf 
    mutable boost::recursive_mutex mut; 
};  

int main(void) 
{ 
    FFTBuf<int> b ; 

    { 
     boost::recursive_mutex::scoped_lock lock1(b.mut); 
     std::cerr << "Locking 1" << std::endl; 

     // here the mutex is locked 1 times 

     { 
      boost::recursive_mutex::scoped_lock lock2(b.mut); 
      std::cerr << "Locking 2" << std::endl; 

      // here the mutex is locked 2 times 

      std::cerr << "Auto UnLocking 2 (by RAII) " << std::endl; 
     } 

     b.exemple(); 

     // here the mutex is locked 1 times 

     std::cerr << "Auto UnLocking 1 (by RAII) " << std::endl; 
    } 

    return 0; 
} 

注意可變互斥的常量方法。

而boost mutex類型有一個scoped_lock typedef,它是很好的unique_lock類型。

4

顧名思義,互斥鎖是recursive,但Lock不是。

這就是說,你在這裏有一個設計問題。鎖定操作會更好,不能從外部訪問。

class SynchronizedInt 
{ 
public: 
    explicit SynchronizedInt(int i = 0): mData(i) {} 

    int get() const 
    { 
    lock_type lock(mMutex); 
    toolbox::ignore_unused_variable_warning(lock); 

    return mData; 
    } 

    void set(int i) 
    { 
    lock_type lock(mMutex); 
    toolbox::ignore_unused_variable_warning(lock); 

    mData = i; 
    } 


private: 
    typedef boost::recursive_mutex mutex_type; 
    typedef boost::unique_lock<mutex_type> lock_type; 

    int mData; 
    mutable mutex_type mMutex; 
}; 

recursive_mutex的要點是允許在一個給定的線程鏈鎖定,如果你有複雜的操作調用對方在某些情況下可能發生。

例如,讓我們添加的調整得到:

int SynchronizedInt::UnitializedValue = -1; 

int SynchronizedInt::get() const 
{ 
    lock_type lock(mMutex); 
    if (mData == UnitializedValue) this->fetchFromCache(); 
    return mData; 
} 

void SynchronizedInt::fetchFromCache() 
{ 
    this->set(this->fetchFromCacheImpl()); 
} 

如果這裏的問題?

  • get獲取關於mMutex
  • 它調用fetchFromCache這就要求set
  • set試圖獲取鎖鎖...

如果我們沒有一個recursive_mutex,這將失敗。

+0

問題是我有一個函數返回一個指針,我需要確保在我的類之外完成的操作的同步。所以這就是爲什麼我需要鎖定和解鎖方法,我把它們放在類裏,以避免在外部代碼中顯式使用boost :: * _ lock。我應該想想更好的設計...... – Kjir 2010-04-08 16:30:51

+0

總是有一種解決方法,你可以將一個裁判計數所有者返回給鎖來保證銷燬。 – 2010-04-09 07:07:51

+0

「_鎖定操作會更好,不能從外部訪問_」如果您需要增加SynchronizedInt,該怎麼辦? – curiousguy 2011-10-22 19:27:03

相關問題