0

CMyBufferオブジェクトへのスレッド排他アクセスには、次の 2 つの方法があります。

ヘッダ:

class CSomeClass
{
//...
public:
    CMyBuffer & LockBuffer();
    void ReleaseBuffer();

private:
    CMyBuffer m_buffer;
    CCriticalSection m_bufferLock;
//...
}

実装:

CMyBuffer & CSomeClass::LockBuffer()
{
    m_bufferLock.Lock();
    return m_buffer;
}

void CSomeClass::ReleaseBuffer()
{
    m_bufferLock.Unlock();
}

使用法:

void someFunction(CSomeClass & sc)
{
    CMyBuffer & buffer = sc.LockBuffer();
    // access buffer
    sc.ReleaseBuffer();
}
  • これについて私が気に入っているのは、ユーザーが関数呼び出しを 1 回だけ行う必要があり、バッファーをロックした後にのみバッファーにアクセスできることです。
  • 私が気に入らないのは、ユーザーが明示的に解放しなければならないことです。

更新: これらの追加の欠点は、Nick Meyer と Martin York によって指摘されました。

  • ユーザーはロックを解除してからバッファを使用できます。
  • ロックを解放する前に例外が発生した場合、バッファーはロックされたままになります。

CSingleLockオブジェクトが範囲外になったときにバッファのロックを解除するオブジェクト(または同様のもの)でそれを行いたいと思います。

どうすればそれができますか?

4

3 に答える 3

2

これを行う1つの方法は、RAIIを使用することです:

class CMyBuffer
{
public:
    void Lock()
    {
        m_bufferLock.Lock();
    }

    void Unlock()
    {
        m_bufferLock.Unlock();
    }

private:
    CCriticalSection m_bufferLock;

};

class LockedBuffer
{
public:
    LockedBuffer(CMyBuffer& myBuffer) : m_myBuffer(myBuffer)
    {
        m_myBuffer.Lock();
    }

    ~LockedBuffer()
    {

        m_myBuffer.Unlock();
    }

    CMyBuffer& getBuffer() 
    {
        return m_myBuffer;
    }

private:
    CMyBuffer& m_myBuffer;

};

class CSomeClass
{
    //...
public:
    LockedBuffer getBuffer();

private:
    CMyBuffer m_buffer;

};


LockedBuffer CSomeClass::getBuffer()
{
    return LockedBuffer(m_buffer);
}

void someFunction(CSomeClass & sc)
{
    LockedBuffer lb = sc.getBuffer();
    CMyBuffer& buffer = lb.getBuffer();
    //Use the buffer, when lb object goes out of scope buffer lock is released
}
于 2009-08-10T15:26:37.010 に答える
1

バッファを表すオブジェクトを使用します。
このオブジェクトが初期化されたらロックを取得し、破棄されたらロックを解除します。
キャスト演算子を追加して、任意の関数呼び出しでバッファーの代わりに使用できるようにします。

#include <iostream>

// Added to just get it to compile
struct CMyBuffer
{    void doStuff() {std::cout << "Stuff\n";}};
struct CCriticalSection
{
        void Lock()     {}
        void Unlock()   {}
};          

class CSomeClass
{
    private:
        CMyBuffer m_buffer;
        CCriticalSection m_bufferLock;

        // Note the friendship.
        friend class CSomeClassBufRef;
};

// The interesting class.
class CSomeClassBufRef
{
    public:
        CSomeClassBufRef(CSomeClass& parent)
            :m_owned(parent)
        {
           // Lock on construction
            m_owned.m_bufferLock.Lock();
        }
        ~CSomeClassBufRef()
        {
            // Unlock on destruction
            m_owned.m_bufferLock.Unlock();
        }
        operator CMyBuffer&()
        {
            // When this object needs to be used as a CMyBuffer cast it.
            return m_owned.m_buffer;
        }
    private:
        CSomeClass&     m_owned;
}; 

void doStuff(CMyBuffer& buf)
{           
    buf.doStuff();
}
int main()
{
    CSomeClass          s;

    // Get a reference to the buffer and auto lock.
    CSomeClassBufRef    b(s);

    // This call auto casts into CMyBuffer
    doStuff(b);

    // But you can explicitly cast into CMyBuffer if you need.
    static_cast<CMyBuffer&>(b).doStuff();
}
于 2009-08-10T16:14:32.687 に答える
1

IMHO、あなたの目標がロックされているときにのみユーザーがバッファにアクセスできないようにすることである場合、あなたはトリッキーな戦いを戦っています. ユーザーが次のことを行っているかどうかを検討してください。

void someFunction(CSomeClass & sc)
{
   CMyBuffer & buffer = sc.LockBuffer();
   sc.ReleaseBuffer();
   buffer.someMutatingMethod(); // Whoops, accessed while unlocked!
}

ユーザーがバッファにアクセスできるようにするには、バッファへの参照を返す必要があります。これは、ロックが解除されるまで保持するという間違いを犯す可能性があります。

とはいえ、次のようなことができるかもしれません。

class CMyBuffer
{
   private:
      void mutateMe();
      CCriticalSection m_CritSec;

   friend class CMySynchronizedBuffer;
};

class CMySynchronizedBuffer
{
   private:
      CMyBuffer & m_Buffer;
      CSingleLock m_Lock

   public:
      CMySynchronizedBuffer (CMyBuffer & buffer)
         : m_Buffer (buffer)
         , m_Lock (&m_Buffer.m_CritSec, TRUE)
      {
      }

      void mutateMe()
      {
         m_Buffer.mutateMe();
      }
};

次のように使用します。

{
   CMyBuffer buffer;  // Or declared elsewhere
   // buffer.mutateMe();  (Can't do this)
   CMySyncrhonizedBuffer synchBuffer (buffer); // Wrap it & lock it
   synchBuffer.mutateMe();  // Now protected by critical section
} // synchBuffer and its CSingleLock member are destroyed and the CS released

これにより、ユーザーは CMySynchronizedBuffer オブジェクトで CMyBuffer オブジェクトをラップして、変更メソッドのいずれかを取得する必要があります。参照を返すことによって基になる CMyBuffer オブジェクトへのアクセスを実際に提供するわけではないため、ロックが解除された後に、ユーザーにハングアップして変更するものを与えるべきではありません。

于 2009-08-10T15:21:13.307 に答える