簡體   English   中英

為什么boost :: recursive_mutex無法正常工作?

[英]Why boost::recursive_mutex is not working as expected?

我有一個自定義類,該類使用增強互斥鎖和此類鎖(僅相關部分):

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

這是輸出:

sb@dex $ ./src/test
Locking
Locked
Locking
terminate called after throwing an instance of 'boost::lock_error'
   what(): boost::lock_error
zsh: abort    ./src/test

為什么會這樣呢? 我對某些概念的理解不正確嗎?

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

就是說,您這里有一個設計問題。 最好不要從外部訪問鎖定操作。

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要點是允許在給定線程中進行鏈鎖定,如果您在某些情況下具有相互調用的復雜操作,則可能會發生這種情況。

例如,讓我們添加調整get:

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 ,這將失敗。

該鎖不應屬於受保護資源,而應屬於調用方,因為您有一個線程調用方。 他們必須使用不同的unique_lock。

unique_lock的目的是使用RAII鎖定和釋放互斥鎖,因此您不必顯式調用解鎖。

在方法體內聲明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;
}

請注意const方法互斥量上的可變項。

Boost互斥鎖類型具有scoped_lock typedef,這是很好的unique_lock類型。

嘗試這個:

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作為類的成員也常常是一個壞主意。

暫無
暫無

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

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