跨平台中对于 互斥量(mutex) 的包装

以下代码在跨平台环境下包装了互斥量(mutex),支持以下平台 linux/windows,vc/gcc/mingw

/**
 * @file -
 * @author jingqi
 * @date 2010-7-9
 */

#ifndef ___HEADFILE___814FCD2E_2F65_4787_93E5_ECDE19588938_
#define ___HEADFILE___814FCD2E_2F65_4787_93E5_ECDE19588938_

#include 
#include 

#if defined(NUT_PLATFORM_OS_WINDOWS)
#  include 
#endif

#if !defined(NUT_PLATFORM_OS_WINDOWS) || defined(NUT_PLATFORM_CC_MINGW)
#  include 
#endif

namespace nut
{

class Mutex
{
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
    HANDLE m_hmutex;
#else
    pthread_mutex_t m_mutex;
#endif

public :
    Mutex ()
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        m_hmutex = ::CreateMutex(NULL, FALSE, NULL);
#else
        ::pthread_mutexattr_t attr;
        ::pthread_mutexattr_init(&attr);
        ::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); /* make the mutex recursive */
        int rs = ::pthread_mutex_init(&m_mutex, &attr);
        assert(0 == rs);
#endif
    }

    ~Mutex ()
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        BOOL rs = ::CloseHandle(m_hmutex);
        assert(rs);
#else
        int rs = ::pthread_mutex_destroy(&m_mutex);
        assert(0 == rs);
#endif
    }

#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
    inline HANDLE innerMutex() { return m_hmutex; }
#else
    inline pthread_mutex_t* innerMutex() { return &m_mutex; }
#endif

    /**
     * lock the mutex, which may blocked the thread
     */
    inline void lock()
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        DWORD rs = ::WaitForSingleObject(m_hmutex, INFINITE);
        assert(WAIT_OBJECT_0 == rs);
#else
        int rs = ::pthread_mutex_lock(&m_mutex);
        assert(0 == rs);
#endif
    }

    /**
     * unlock the mutex
     */
    inline void unlock()
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        BOOL rs = ::ReleaseMutex(m_hmutex);
        assert(rs);
#else
        int rs = ::pthread_mutex_unlock(&m_mutex);
        assert(0 == rs);
#endif
    }

    /**
     * try lock the mutex
     * @return
     *      true, if lock successed
     */
    inline bool trylock()
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        return WAIT_OBJECT_0 == ::WaitForSingleObject(m_hmutex, 0);
#else
        int lock_result = ::pthread_mutex_trylock(&m_mutex);
        /** returned values :
         *  0, lock ok
         *  EBUSY, The mutex is already locked.
         *  EINVAL, Mutex is not an initialized mutex.
         *  EFAULT, Mutex is an invalid pointer.
         */
        return 0 == lock_result;
#endif
    }

#if defined(NUT_PLATFORM_OS_WINDOWS) && defined(NUT_PLATFORM_CC_MINGW)
    /** time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds */
#   define PTW32_TIMESPEC_TO_FILETIME_OFFSET (LONGLONG)((((LONGLONG) 27111902LL << 32)+(LONGLONG) 3577643008LL ))
    /**
     * mingw 没有定义clock_gettime(), 这里参考其pthread_mutex_timedlock.c ptw32_relmillisecs.c 的实现
     */
    static void clock_getrealtime(struct timespec *ts)
    {
        assert(NULL != ts);
        SYSTEMTIME st;
        ::GetSystemTime(&st);
        FILETIME ft;
        ::SystemTimeToFileTime(&st, &ft);
        ts->tv_sec = (int)((*(LONGLONG *)&ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000LL);
        ts->tv_nsec = (int)((*(LONGLONG *)&ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET - ((LONGLONG)ts->tv_sec * (LONGLONG)10000000LL)) * 100);
    }
#   undef PTW32_TIMESPEC_TO_FILETIME_OFFSET
#endif

    /**
     * try lock the mutex in given time
     * @param s
     *      The timeout value in seconds
     * @param ms
     *      The timeout value in milliseconds
     * @return
     *      true, if lock successed
     */
    inline bool timedlock(unsigned s, unsigned ms = 0)
    {
#if defined(NUT_PLATFORM_OS_WINDOWS) && !defined(NUT_PLATFORM_CC_MINGW)
        DWORD dwMilliseconds = s * 1000 + ms;
        return WAIT_OBJECT_0 == ::WaitForSingleObject(m_hmutex, dwMilliseconds);
#else
        struct timespec abstime;
#   if defined(NUT_PLATFORM_OS_WINDOWS) && defined(NUT_PLATFORM_CC_MINGW)
        clock_getrealtime(&abstime);
#   else
        clock_gettime(CLOCK_REALTIME, &abstime);
#   endif
        abstime.tv_sec += s;
        abstime.tv_nsec += ((long)ms) * 1000 * 1000;
        int lock_result = ::pthread_mutex_timedlock(&m_mutex, &abstime);
        /** returned values :
         *  0, lock ok
         *  EAGAIN, The mutex couldn't be acquired because the maximum number of recursive locks for the mutex has been exceeded.
         *  EDEADLK, The current thread already owns the mutex.
         *  EINVAL, The mutex was created with the protocol attribute having the value PTHREAD_PRIO_PROTECT and the calling thread's priority is higher than the mutex' current priority ceiling; the process or thread would have blocked, and the abs_timeout parameter specified a nanoseconds field value less than zero or greater than or equal to 1000 million; or the value specified by mutex doesn't refer to an initialized mutex object.
         *  ETIMEDOUT, The mutex couldn't be locked before the specified timeout expired
         */
        return 0 == lock_result;
#endif
    }
};

}

#endif /* head file guarder */


说明,

  1. 跨平台宏(platform.hpp)的定义参见另一篇博文,当然截取代码实现时可以换成自己习惯的定义
  2. windows/vc下使用的是系统API提供的互斥量,linux和windows/mingw下使用的是pthread多线程库提供的互斥量
  3. 基本支持 lock(), trylock(), timedlock(), unlock() 功能
  4. pthread_mutex_t 默认属性是不支持锁重入的,所以有初始化属性时添加了锁重入支持
  5. windows/mingw下没有提供clock_gettime() 函数来获取精确的当前时间,所以参照其他函数实现了一个,以便实现 timedlock() 功能

你可能感兴趣的:(多线程,C++,nut)