我有一台服务器在端口上侦听请求。当请求进入时,它被分派到单例类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)数据结构还是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)我应该按引用还是按对象返回?
   无论哪种情况,请说明。

提前致谢。

最佳答案

1]如果该类是单例并且mRootData在该类内,那么Mutex gaurd是否真的必要?


是的,因为一个线程可以调用process(),而另一个线程可以调用refresh()


  2]我应该保护i)数据结构还是ii)访问数据结构的功能。


Mutex旨在保护公用代码路径,即访问共享数据的功能(的一部分)。当在同一代码块中发生锁定和释放时,最容易使用。将它们放入不同的方法几乎是死锁的公开邀请,因为调用者必须确保正确释放每个锁。

更新:如果GetRootDataSetRootData也是公共函数,那么用当前形式的互斥体来保护它们没有太多意义。问题是,您正在发布对共享数据的引用,在此之后,调用者可能会做什么以及何时使用共享数据完全不受您的控制。来自100个不同线程的100个调用者可以存储对mRootData的引用,并决定同时对其进行修改!同样,在调用SetRootData之后,调用者可以保留对根数据的引用,并可以随时访问它,而您甚至都不会注意到(最终由于数据损坏或死锁而导致的除外)。

您有以下选择(除了祈祷客户友好,不要对可怜的单身人士做讨厌的事情;-)


在getter和setter中创建mRootData的深层副本。这将数据限制在单例中,可以在其中使用锁进行保护。 GetRootData的OTOH调用者将获得数据快照,并且他们看不到后续更改-您可能接受或不接受。
重写RootData以使其成为线程安全的,则单例无需再关心线程安全(在其当前设置中-如果它具有其他数据成员,则情况可能会有所不同)。


更新2:


或完全删除getter和setter(可能连同将数据处理方法从其他类移到单例中,可以通过互斥体适当地保护它们)。除非您绝对需要其他方直接访问mRootData,否则这将是最简单和最安全的。

关于c++ - 多线程环境中对Singleton资源的互斥保护,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3310350/

10-16 11:29