c++ poco Mutex Related Source Analysis

Keywords: Attribute Linux

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

Posted by ttroy on Sun, 19 May 2019 06:06:28 -0700