How do I make calling InitializeCriticalSection() thread safe? [modified]
-
I have a static class I use for caching data. This will now be accessed from multiple threads which means I need to add a CRITICAL_SECTION to make updating the cache thread safe. I now have the problem of who initialises the CRITICAL_SECTION given a static class doesn't have a constructor.
std::map<int,std::string> CMY_CACHE::m_cache_map; CRITICAL_SECTION CMY_CACHE::m_critical_section; class CMY_CACHE { private: static std::map<int,std::string> m_cache_map; static CRITICAL_SECTION m_critical_section; //<-- Where do I initialize this? public: std::string read(int index) { EnterCriticalSection(&m_critical_section); std::map<int,std::string>::iterator it=m_cache_map.find(index); if (it==m_cache_map.end()) { // Add value to cache // Adjust iterator } LeaveCriticalSection(&m_critical_section); return(it->second); } ... // The following call could be issued by multiple threads std::string s=CMY_CACHE::read(0);
modified on Friday, October 16, 2009 8:28 AM
-
I have a static class I use for caching data. This will now be accessed from multiple threads which means I need to add a CRITICAL_SECTION to make updating the cache thread safe. I now have the problem of who initialises the CRITICAL_SECTION given a static class doesn't have a constructor.
std::map<int,std::string> CMY_CACHE::m_cache_map; CRITICAL_SECTION CMY_CACHE::m_critical_section; class CMY_CACHE { private: static std::map<int,std::string> m_cache_map; static CRITICAL_SECTION m_critical_section; //<-- Where do I initialize this? public: std::string read(int index) { EnterCriticalSection(&m_critical_section); std::map<int,std::string>::iterator it=m_cache_map.find(index); if (it==m_cache_map.end()) { // Add value to cache // Adjust iterator } LeaveCriticalSection(&m_critical_section); return(it->second); } ... // The following call could be issued by multiple threads std::string s=CMY_CACHE::read(0);
modified on Friday, October 16, 2009 8:28 AM
Instead of having all members static, you could use a singleton pattern: it is a design pattern that makes sure your class is created only once. I won't go into much details here but I suggest you google for "Thread safe singleton pattern". Basically, you add a public static function that returns a pointer to your single instance (
CMY_CACHE* CMY_CACHE::instance
for example). Once your class is a singleton, you can simply create your critical section in the class constructor. Your read method is no more a static function and you call it this way:CMY_CACHE::instance()->read(0);
Cédric Moonen Software developer
Charting control [v2.0] OpenGL game tutorial in C++ -
I have a static class I use for caching data. This will now be accessed from multiple threads which means I need to add a CRITICAL_SECTION to make updating the cache thread safe. I now have the problem of who initialises the CRITICAL_SECTION given a static class doesn't have a constructor.
std::map<int,std::string> CMY_CACHE::m_cache_map; CRITICAL_SECTION CMY_CACHE::m_critical_section; class CMY_CACHE { private: static std::map<int,std::string> m_cache_map; static CRITICAL_SECTION m_critical_section; //<-- Where do I initialize this? public: std::string read(int index) { EnterCriticalSection(&m_critical_section); std::map<int,std::string>::iterator it=m_cache_map.find(index); if (it==m_cache_map.end()) { // Add value to cache // Adjust iterator } LeaveCriticalSection(&m_critical_section); return(it->second); } ... // The following call could be issued by multiple threads std::string s=CMY_CACHE::read(0);
modified on Friday, October 16, 2009 8:28 AM
The quick & dirty (you're warned...) trick: wrap the
CRITICAL_SECTION
in a struct and do initialization (cleanup) in struct constructor (destructor). :)If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
[My articles] -
I have a static class I use for caching data. This will now be accessed from multiple threads which means I need to add a CRITICAL_SECTION to make updating the cache thread safe. I now have the problem of who initialises the CRITICAL_SECTION given a static class doesn't have a constructor.
std::map<int,std::string> CMY_CACHE::m_cache_map; CRITICAL_SECTION CMY_CACHE::m_critical_section; class CMY_CACHE { private: static std::map<int,std::string> m_cache_map; static CRITICAL_SECTION m_critical_section; //<-- Where do I initialize this? public: std::string read(int index) { EnterCriticalSection(&m_critical_section); std::map<int,std::string>::iterator it=m_cache_map.find(index); if (it==m_cache_map.end()) { // Add value to cache // Adjust iterator } LeaveCriticalSection(&m_critical_section); return(it->second); } ... // The following call could be issued by multiple threads std::string s=CMY_CACHE::read(0);
modified on Friday, October 16, 2009 8:28 AM
... or, instead of a singleton, you could write a CRITICAL_SECTION wrapper class. e.g. something like
class CS : public CRITICAL_SECTION
{
public:
CS( ulong SPINCOUNT = 4000 ) {
#ifdef _DEBUG
::InitializeCriticalSectionEx(this, SPINCOUNT, 0);
#else
::InitializeCriticalSectionEx(this, SPINCOUNT, CRITICAL_SECTION_NO_DEBUG_INFO);
#endif
}
~CS() {
::DeleteCriticalSection(this);
}
};then use it wherever you used CRITICAL_SECTION.
...cmk The idea that I can be presented with a problem, set out to logically solve it with the tools at hand, and wind up with a program that could not be legally used because someone else followed the same logical steps some years ago and filed for a patent on it is horrifying. - John Carmack