我有两种方法可以对CMyBuffer
对象进行线程独占访问:
部首:
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();
}
更新:Nick Meyer和Martin York指出了这些额外的缺点:
我想用CSingleLock
对象(或类似的东西)来做,当对象超出范围时,它会解锁缓冲区。
怎么可能这样做?
答案 0 :(得分:2)
执行此操作的一种方法是使用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
}
答案 1 :(得分:1)
恕我直言,如果您的目标是阻止用户仅在锁定时访问缓冲区,那么您正在进行一场棘手的战斗。考虑用户是否:
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
这会强制用户将CMyBuffer对象包装在CMySynchronizedBuffer对象中,以获取其任何变异方法。由于它实际上并不通过返回引用来提供对底层CMyBuffer对象的访问,因此在释放锁之后它不应该给用户任何挂起和变异的内容。
答案 2 :(得分:1)
使用代表缓冲区的对象 当这个obejct被初始化时获得锁定,当它被销毁时释放锁定 添加一个强制转换运算符,以便在任何函数调用中使用它来代替缓冲区:
#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();
}