I have a server listening on a port for request. When the request comes in, it is dispatched to a singleton class Singleton. This Singleton class has a data structure RootData.
class Singleton {
void process();
void refresh();
private:
RootData mRootData;
}
In the class there are two functions: process: Work with the mRootData to do some processing and refresh: called periodically from another thread to refresh the mRootData with the latest changes from Database.
It is required that the access to mRootData be gaurded by Mutex.
I have the following questions:
1] If the class is a singleton and mRootData is inside that class, is the Mutex gaurd really necessary?
I know it is necessary for conflict between refresh/process. But from the server, i think there will be only one call to process happening at any give time ( coz the class is Singleton) Please correct me if my understanding is wrong.
2] Should i protect the i) data structure OR ii) function accessing the data structure. E.g.
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] If the answer to above is i) should i return by reference or by object?
Please explain in either case.
Thanks in advance.
Yes it is, since one thread may call
process()while another is callingrefresh().Mutex is meant to protect a common code path, i.e. (part of) the function accessing the shared data. And it is easiest to use when locking and releasing happens within the same code block. Putting them into different methods is almost an open invitation for deadlocks, since it is up to the caller to ensure that every lock is properly released.Update: if
GetRootDataandSetRootDataare public functions too, there is not much point to guard them with mutexes in their current form. The problem is, you are publishing a reference to the shared data, after which it is completely out of your control what and when the callers may do with it. 100 callers from 100 different threads may store a reference tomRootDataand decide to modify it at the same time! Similarly, after callingSetRootDatathe caller may retain the reference to the root data, and access it anytime, without you even noticing (except eventually from a data corruption or deadlock…).You have the following options (apart from praying that the clients be nice and don’t do nasty things to your poor singleton 😉
mRootDataboth in the getter and the setter. This keeps the data confined to the singleton, where it can be guarded with locks. OTOH callers ofGetRootDataget a snapshot of the data, and subsequent changes are not visible to them – this may or may not be acceptable to you.RootDatato make it thread safe, then the singleton needs to care no more about thread safety (in its current setup – if it has other data members, the picture may be different).Update2:
mRootDatadirectly.