1. overview
Lock mechanism is a synchronization mechanism for controlling access to shared resources in multi-threaded concurrent scenarios. Mutex is similar to FastMutex in that they can automatically lock and unlock mutexes with the help of ScopedLock template classes. The difference is that Mutex is recursive, which means that the same mutex is allowed to be locked multiple times by the same thread; FastMutex is non-recursive, which means that if the same thread tries to lock another mutex that has been locked, deadlock will occur.
2. classes of Graphs
2.1) Mutex inherits privately from MutexImpl, and the class contains a CopedLock class declaration with a template parameter of Mutex.
2.2) FastMutex inherits privately from FastMutexImpl, which contains the CopedLock class declaration with the template parameter FastMutex, and FastMutexImpl inherits publicly from MutexImpl.
2.3) The MutexImpl class encapsulates system calls related to linux mutex lock.
2.4) The destructor and constructor of the ScopedLock template class lock and unlock the incoming "lock object".
3. Interface parsing
template <class M>
class ScopedLock
/// A class that simplifies thread synchronization
/// with a mutex.
/// The constructor accepts a Mutex (and optionally
/// a timeout value in milliseconds) and locks it.
/// The destructor unlocks the mutex.
{
public:
explicit ScopedLock(M& mutex): _mutex(mutex)
{
_mutex.lock();
}
ScopedLock(M& mutex, long milliseconds): _mutex(mutex)
{
_mutex.lock(milliseconds);
}
~ScopedLock()
{
try
{
_mutex.unlock();
}
catch (...)
{
poco_unexpected();
}
}
private:
M& _mutex;
ScopedLock();
ScopedLock(const ScopedLock&);
ScopedLock& operator = (const ScopedLock&);
};
3.1Mutex
3.1.1 constructor
Mutex::Mutex()
{
}
MutexImpl::MutexImpl()
{
#if defined(POCO_VXWORKS)
/// ... ...
#endif
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if defined(PTHREAD_MUTEX_RECURSIVE_NP)
/// ... ...
#elif !defined(POCO_VXWORKS)
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#endif
if (pthread_mutex_init(&_mutex, &attr))
{
pthread_mutexattr_destroy(&attr);
throw SystemException("cannot create mutex");
}
pthread_mutexattr_destroy(&attr);
}
Mutex's constructor is sketchy; MutexImpl's constructor mainly completes the following tasks:
1) pthread_mutexattr_init() initializes attribute object attr
2) pthread_mutexattr_settype() Sets the attribute object attr to PTHREAD_MUTEX_RECURSIVE
3) pthread_mutex_init() initializes mutex with attribute attr
4) pthread_mutexattr_destroy() destroy attribute object attr
3.1.2 Destructive Function
Mutex::~Mutex()
{
}
MutexImpl::~MutexImpl()
{
pthread_mutex_destroy(&_mutex);
}
Mutex's destructor is sketchy; MutexImpl's destructor mainly completes the following tasks:
1) pthread_mutex_destroy() destroy mutex
3.1.3 lock () function
inline void Mutex::lock()
{
lockImpl();
}
inline void MutexImpl::lockImpl()
{
if (pthread_mutex_lock(&_mutex))
throw SystemException("cannot lock mutex");
}
MutexImpl's lockImpl function mainly completes the following tasks:
1) pthread_mutex_lock() applies for mutex in a blocking manner
3.1.4 lock (long milliseconds) function
inline void Mutex::lock(long milliseconds)
{
if (!tryLockImpl(milliseconds))
throw TimeoutException();
}
bool MutexImpl::tryLockImpl(long milliseconds)
{
#if defined(POCO_HAVE_MUTEX_TIMEOUT)
struct timespec abstime;
#if defined(POCO_HAVE_CLOCK_GETTIME)
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += milliseconds / 1000;
abstime.tv_nsec += (milliseconds % 1000)*1000000;
if (abstime.tv_nsec >= 1000000000)
{
abstime.tv_nsec -= 1000000000;
abstime.tv_sec++;
}
#else
/// ... ...
#endif
int rc = pthread_mutex_timedlock(&_mutex, &abstime);
if (rc == 0)
return true;
else if (rc == ETIMEDOUT)
return false;
else
throw SystemException("cannot lock mutex");
#else
/// ... ...
#endif
}
MutexImpl's tryLockImpl(long milliseconds) function mainly completes the following tasks:
1) Calculate the absolute time abstime when the waiting expires
2) pthread_mutex_timedlock() applies for mutex in a blocking manner and returns the error code ETIMEDOUT when it reaches the timeout value.
3.1.5 tryLock () function
inline bool Mutex::tryLock()
{
return tryLockImpl();
}
inline bool MutexImpl::tryLockImpl()
{
int rc = pthread_mutex_trylock(&_mutex);
if (rc == 0)
return true;
else if (rc == EBUSY)
return false;
else
throw SystemException("cannot lock mutex");
}
MutexImpl's tryLockImpl function mainly completes the following tasks:
1) pthread_mutex_trylock() applies for mutex in a non-blocking manner
3.1.6 tryLock (long milliseconds) function
inline bool Mutex::tryLock(long milliseconds)
{
return tryLockImpl(milliseconds);
}
MutexImpl's tryLockImpl(long milliseconds) function mainly completes the following tasks: the same as 3.1.4
3.1.7 unlock () function
inline void Mutex::unlock()
{
unlockImpl();
}
inline void MutexImpl::unlockImpl()
{
if (pthread_mutex_unlock(&_mutex))
throw SystemException("cannot unlock mutex");
}
MutexImpl's unlockImpl function mainly completes the following tasks:
1) pthread_mutex_unlock() releases mutex
3.2FastMutex
3.2.1 constructor
FastMutex::FastMutex()
{
}
FastMutexImpl::FastMutexImpl(): MutexImpl(true)
{
}
MutexImpl::MutexImpl(bool fast)
{
#if defined(POCO_VXWORKS)
/// ... ...
#endif
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if defined(PTHREAD_MUTEX_RECURSIVE_NP)
/// ... ...
#elif !defined(POCO_VXWORKS)
pthread_mutexattr_settype(&attr, fast ? PTHREAD_MUTEX_NORMAL : PTHREAD_MUTEX_RECURSIVE);
#endif
if (pthread_mutex_init(&_mutex, &attr))
{
pthread_mutexattr_destroy(&attr);
throw SystemException("cannot create mutex");
}
pthread_mutexattr_destroy(&attr);
}
The constructors of FastMutex and FastMutexImpl are sketchy. The constructors of MutexImpl mainly accomplish the following tasks:
1) pthread_mutexattr_init() initializes attribute object attr
2) pthread_mutexattr_settype() Sets the attribute object attr to PTHREAD_MUTEX_NORMAL (the main difference between Mutex and FastMutex)
3) pthread_mutex_init() initializes mutex with attribute attr
4) pthread_mutexattr_destroy() destroy attribute object attr
3.2.2 Destructive Function
FastMutex::~FastMutex()
{
}
FastMutexImpl::~FastMutexImpl()
{
}
MutexImpl::~MutexImpl()
{
pthread_mutex_destroy(&_mutex);
}
The destructors of FastMutex and FastMutexImpl are outlined. The destructors of MutexImpl mainly accomplish the following tasks:
1) pthread_mutex_destroy() destroy mutex
3.2.3 lock () function
inline void FastMutex::lock()
{
lockImpl();
}
inline void MutexImpl::lockImpl()
{
if (pthread_mutex_lock(&_mutex))
throw SystemException("cannot lock mutex");
}
MutexImpl's lockImpl function mainly completes the following tasks:
1) pthread_mutex_lock() applies for mutex in a blocking manner
3.2.4 lock (long milliseconds) function
inline void FastMutex::lock(long milliseconds)
{
if (!tryLockImpl(milliseconds))
throw TimeoutException();
}
bool MutexImpl::tryLockImpl(long milliseconds)
{
#if defined(POCO_HAVE_MUTEX_TIMEOUT)
struct timespec abstime;
#if defined(POCO_HAVE_CLOCK_GETTIME)
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += milliseconds / 1000;
abstime.tv_nsec += (milliseconds % 1000)*1000000;
if (abstime.tv_nsec >= 1000000000)
{
abstime.tv_nsec -= 1000000000;
abstime.tv_sec++;
}
#else
/// ... ...
#endif
int rc = pthread_mutex_timedlock(&_mutex, &abstime);
if (rc == 0)
return true;
else if (rc == ETIMEDOUT)
return false;
else
throw SystemException("cannot lock mutex");
#else
/// ... ...
#endif
}
MutexImpl's tryLockImpl(long milliseconds) function mainly completes the following tasks:
1) Calculate the absolute time abstime when the waiting expires
2) pthread_mutex_timedlock() applies for mutex in a blocking manner and returns the error code ETIMEDOUT when it reaches the timeout value.
3.2.5 tryLock () function
inline bool FastMutex::tryLock()
{
return tryLockImpl();
}
inline bool MutexImpl::tryLockImpl()
{
int rc = pthread_mutex_trylock(&_mutex);
if (rc == 0)
return true;
else if (rc == EBUSY)
return false;
else
throw SystemException("cannot lock mutex");
}
MutexImpl's tryLockImpl function mainly completes the following tasks:
1) pthread_mutex_trylock() applies for mutex in a non-blocking manner
3.2.6 tryLock (long milliseconds) function
inline bool FastMutex::tryLock(long milliseconds)
{
return tryLockImpl(milliseconds);
}
MutexImpl's tryLockImpl(long milliseconds) function mainly completes the following tasks: the same as 3.2.4
3.2.7 unlock () function
inline void FastMutex::unlock()
{
unlockImpl();
}
inline void MutexImpl::unlockImpl()
{
if (pthread_mutex_unlock(&_mutex))
throw SystemException("cannot unlock mutex");
}
MutexImpl's unlockImpl function mainly completes the following tasks:
1) pthread_mutex_unlock() releases mutex