Re: A few questions about singletons...
"Michael Doubez" <michael.doubez@free.fr> wrote in message
news:5b98df17-4599-49bc-ba58-a5a31cc1d800@k17g2000yqb.googlegroups.com...
On 25 sep, 20:45, Joshua Maurice <joshuamaur...@gmail.com> wrote:
[...]
Alternatively, use the more complex designs of Chris M.
Thomasson, which just guarantee single correct construction with
minimal overhead. There are several, depending on platform, and
exactly what guarantees you want.
I have seen the code mentioned and it supposes that initialisation of
the mutex is atomic.
If I replace in the header:
typedef HANDLE pthread_mutex_t;
#define PTHREAD_MUTEX_INITIALIZER CreateMutex(/* params */)
You see the problem with:
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
In fact, it is possible that two mutex will be created and the mutex
is then useless.
In practice, IIRC it does work with the usual libpthread.
Yes. The code I posted assumes that it will always be run under a POSIX
compliant platform. However, since you bring up Windows, well, there is a
hack one can use to dynamically and safely create a mutex in an atomic
fashion:
____________________________________________________________________
class win_dcl_mutex
{
HANDLE m_mutex;
private:
static std::string prv_get_name()
{
std::ostringstream name;
name << "DCL_MUTEX_" << GetCurrentProcessId();
return name.str();
}
public:
win_dcl_mutex() throw()
: m_mutex(CreateMutex(NULL, TRUE, prv_get_name().c_str()))
{
if (! m_mutex)
{
assert(m_mutex);
std::unexpected();
}
else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if (WaitForSingleObject(m_mutex, INFINITE) !=
WAIT_OBJECT_0)
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
}
}
~win_dcl_mutex() throw()
{
if (! ReleaseMutex(m_mutex))
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
if (! CloseHandle(m_mutex))
{
assert(m_mutex);
std::unexpected();
}
}
};
____________________________________________________________________
You would use this hack in the slow path of the DCL algorithm. You can make
this technique more fine grain by adding something to the constructor which
would further identify this mutex beyond using the current process id.
Something like:
____________________________________________________________________
class win_dcl_mutex
{
HANDLE m_mutex;
private:
template<typename T>
static std::string prv_get_name(T const& id)
{
std::ostringstream name;
name << "DCL_MUTEX_" << GetCurrentProcessId() << "_" << id;
return name.str();
}
public:
template<typename T>
win_dcl_mutex(T const& id) throw()
: m_mutex(CreateMutex(NULL, TRUE, prv_get_name(id).c_str()))
{
if (! m_mutex)
{
assert(m_mutex);
std::unexpected();
}
else if (GetLastError() == ERROR_ALREADY_EXISTS)
{
if (WaitForSingleObject(m_mutex, INFINITE) !=
WAIT_OBJECT_0)
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
}
}
~win_dcl_mutex() throw()
{
if (! ReleaseMutex(m_mutex))
{
assert(m_mutex);
CloseHandle(m_mutex);
std::unexpected();
}
if (! CloseHandle(m_mutex))
{
assert(m_mutex);
std::unexpected();
}
}
};
____________________________________________________________________
[...]