我有一台服务器在端口上侦听请求。请求进入时,会将其分派给单个类Singleton
。此Singleton
类具有数据结构RootData
。
class Singleton { void process(); void refresh();
private: RootData mRootData; }
在类中有两个函数:process
:使用mRootData进行一些处理和refresh
:从另一个线程定期调用,用数据库中的最新更改刷新mRootData。
要求Mutex对mRootData
的访问权限进行调整。
我有以下问题:
1]如果类是单例并且mRootData在该类中,那么Mutex gaurd真的有必要吗? 我知道刷新/处理之间存在冲突是必要的。但是从服务器来看,我认为在任何给定的时间只会有一个调用过程发生(因为该类是Singleton)如果我的理解是错误的,请纠正我。
2]我应该保护i)数据结构 OR ii)访问数据结构的功能。例如。
i) const RootData& GetRootData()
{
ACE_Read_Guard guard(m_oMutexReadWriteLock);
return mRootData;
// Mutex is released when this function returns
}
// Similarly Write lock for SetRootData()
ii) void process()
{
ACE_Read_Guard guard(m_oMutexReadWriteLock);
// use mRootData and do processing
// GetRootData() and SetRootData() wont be mutex protected.
// Mutex is released when this function returns
}
3]如果上述答案是i)我应该通过引用还是按对象返回? 请在两种情况下解释。
提前致谢。
答案 0 :(得分:1)
1]如果类是单例并且mRootData在该类中,那么Mutex gaurd真的有必要吗?
是的,因为一个主题可能会调用process()
而另一个主持人正在调用refresh()
。
2]我应该保护i)数据结构还是ii)访问数据结构的功能。
Mutex旨在保护公共代码路径,即访问共享数据的函数(的一部分)。当锁定和释放发生在同一代码块中时,它最容易使用。将它们置于不同的方法几乎是一个公开的死锁邀请,因为由调用者来确保每个锁都被正确释放。
更新:如果GetRootData
和SetRootData
也是公共功能,那么用当前形式的互斥锁来保护它们并不重要。问题是,您正在发布对共享数据的引用,之后完全无法控制调用者可以使用它的时间和时间。来自100个不同线程的100个调用者可以存储对mRootData
的引用,并决定同时修改它!类似地,在调用SetRootData
之后,调用者可以保留对根数据的引用,并随时访问它,甚至不会注意到(最终除了数据损坏或死锁......)。
你有以下选择(除了祈祷客户很好,不要对你可怜的单身人士做坏事; - )
mRootData
的深层副本。这样可以将数据限制在单例中,可以用锁来保护数据。 GetRootData
的OTOH呼叫者获取数据的快照,并且后续更改对他们不可见 - 这可能是您可能接受的,也可能是不可接受的。RootData
以使其线程安全,然后单例不再需要关心线程安全(在其当前设置中 - 如果它有其他数据成员,则图片可能不同)。Update2 :
mRootData
。答案 1 :(得分:0)
1。)是的,互斥是必要的。虽然在任何时候都只存在一个类的实例,但多个线程仍然可以同时在该实例上调用process()
(除非您设计应用程序以便永远不会发生)。
2.。)无论何时使用该值,都应使用互斥锁保护它。
但是,您没有在上面的类声明中提到GetRootData和SetRootData。这些是私有的(仅在类中使用来访问数据)还是公共的(允许其他代码直接访问数据)?
如果您需要通过公开GetRootData()函数来提供对数据的外部访问,那么您需要返回一个副本,或者您的调用者可以在锁定释放后存储引用并操作数据。当然,他们对数据所做的更改不会反映在单例内,这可能不是你想要的。