Mutex的简单封装

/*
 * CMutex.h
 * Process level lock
 */
#ifndef UTIL_MUTEX_H
#define UTIL_MUTEX_H

#include "../common/Common.h"

class CMutex
{
public:

    /**
     * Check if mutex exists
     */
    static int Exists(
        const char * pszName,
        bool * bExist,
        int proj_id = -1/* Linux only */
        );

public:
    CMutex();

    ~CMutex();

    const char * GetName() const
    {
        return m_strName.c_str();
    }

    /**
     * Open mutex
     */
    int OpenIt(
        const char * pszName,
        int proj_id = -1 /* Linux Only */
        );

    /**
     * Create mutex if not exists
     */
    int Create(
        const char * pszName,
        int proj_id = -1 /* Linux Only */
        );

    void Lock();

    void Unlock();

private:
    CMutex(const CMutex &);
    CMutex & operator=(const CMutex &);

private:
    static std::string m_str_path;
    std::string    m_strName;

#if defined(_WIN32)
    HANDLE        m_hMutex;
#endif
#if defined(_LINUX)
    int m_sem_id;
#endif

};

template<class TYPE>
class CMutexGuard
{
public:
    CMutexGuard(TYPE & rTheMutex):m_Mutex(rTheMutex)
    {
        m_Mutex.Lock();
    }

    ~CMutexGuard()
    {
        m_Mutex.Unlock();
    }

private:
    CMutexGuard();
    //CMutexGuard(const CMutexGuard &);
    //CMutexGuard & operator=(const CMutexGuard &);

private:
    TYPE& m_Mutex;
};

#endif // _MUTEX_H
/*
 * CMutex
 * Process level lock
 */

#include "CMutex.h"

#include "../common/Common.h"
#include "Logger.h"



/************************************************************************/
/* Windows                                                                 */
/************************************************************************/

int CMutex::Exists(
    const char * pszName,
    bool * bExist,
    int proj_id/* Linux only */
    )
{

//Windows
#if defined(_WIN32)
        DWORD dwErrCode = 0;
        HANDLE hMutex = ::OpenMutexA(MUTEX_ALL_ACCESS, FALSE, pszName);
        dwErrCode = GetLastError();

        if (hMutex == NULL)
        {
            if (dwErrCode == ERROR_FILE_NOT_FOUND)
            {
                *bExist = false;
                return 0;
            }
            else
            {
                *bExist = true;
                return 0;
            }
        }

        ::CloseHandle(hMutex);
        *bExist = true;
        return 0;
#endif
#if defined(_LINUX)

        key_t key = ftok(pszName, proj_id);

        if (key == -1)
        {
            return -1;
        }

        if (semget(key, 0, 0666) == -1)
        {
            if (errno == ENOENT)
            {
                *bExist = false;
                return 0;
            }
            else
            {
                *bExist = true;
                return 0;
            }
        }

        *bExist = true;
        return 0;
#endif

}

CMutex::CMutex()
{
#if defined(_WIN32)
    m_hMutex = NULL;
#endif
#if defined(_LINUX)
    m_sem_id = -1;
#endif
}

CMutex::~CMutex()
{
#if defined(_WIN32)
    if (m_hMutex != NULL)
    {
        ::CloseHandle(m_hMutex);
        m_hMutex = NULL;
    }
#endif
#if defined(_LINUX)
    if (m_sem_id != -1)
    {
        //Do not delete
        //semctl(m_sem_id, 0, IPC_RMID, NULL);
        m_sem_id = -1;
    }
#endif
}

/**
* Open mutex
*/
int CMutex::OpenIt(
    const char * pszName,
    int proj_id/* Linux Only */
    )
{
    m_strName = pszName;

#if defined(_WIN32)
    DWORD dwErrCode = 0;

    //Try to open a mutex with name xxx, if not found then create one.
    m_hMutex = ::OpenMutexA(MUTEX_ALL_ACCESS, FALSE, m_strName.c_str());
    dwErrCode = GetLastError();

    if (m_hMutex == NULL)
    {
        LOG_ERR("CMutex::OpenMutexA %s failed, err=%d",
            m_strName.c_str(), dwErrCode);
        return -1;
    }
    return 0;
#endif

#if defined(_LINUX)
    if (proj_id == -1)
    {
        LOG_ERR("Invalid proj_id:%d", proj_id);
        return -1;
    }

    key_t key = ftok(m_strName.c_str(), proj_id);

    if (-1 == key)
    {
        return -1;
    }

    m_sem_id = semget(key, 1, 00666);

    if (m_sem_id == -1)
    {
        LOG_ERR("CMutex::semget failed, err=%d", errno);
        return -1;
    }
    return 0;
#endif
}

/**
 * Create mutex if not exists
 */
int CMutex::Create(
    const char * pszName,
    int proj_id /* Linux Only */
    )
{
    m_strName = pszName;

//Windows
#if defined(_WIN32)
        DWORD dwErrCode = 0;

        //Try to open a mutex with name xxx, if not found then create one.
        m_hMutex = ::OpenMutexA(MUTEX_ALL_ACCESS, FALSE, m_strName.c_str());
        dwErrCode = GetLastError();

        if (m_hMutex == NULL)
        {
            if (dwErrCode == ERROR_FILE_NOT_FOUND)
            {
                // Windows security info, create a empty security, so that the others
                // can assess it
                SECURITY_ATTRIBUTES secAttr;
                char secDesc[SECURITY_DESCRIPTOR_MIN_LENGTH];
                secAttr.nLength = sizeof(secAttr);
                secAttr.bInheritHandle = FALSE;
                secAttr.lpSecurityDescriptor = &secDesc;
                InitializeSecurityDescriptor(secAttr.lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
                SetSecurityDescriptorDacl(secAttr.lpSecurityDescriptor, TRUE, 0, FALSE);

                m_hMutex = ::CreateMutexA(&secAttr, FALSE, m_strName.c_str());
                dwErrCode = GetLastError();
                if (NULL == m_hMutex)
                {
                    LOG_TRACE("CreateMutex %s failed, err=%d", m_strName.c_str(), dwErrCode);
                    return -1;
                }

                return 0;
            }
            else
            {
                LOG_TRACE("OpenMutex %s failed, err=%d", m_strName.c_str(), dwErrCode);
                return -1;
            }
        }

        return 0;
#endif
#if defined(_LINUX)
        if (proj_id == -1)
        {
            LOG_TRACE("Invalid proj_id:%d", proj_id);
            return -1;
        }

        key_t key = ftok(m_strName.c_str(), proj_id);

        if (-1 == key)
        {
            return -1;
        }

        m_sem_id = semget(key, 1, IPC_CREAT | IPC_EXCL | 00666);

        if (m_sem_id == -1)
        {
            if (errno != EEXIST)
            {
                LOG_TRACE("semget(create) failed,err=%d", errno);
                return -1;
            }

            m_sem_id = semget(key, 1, IPC_CREAT | 00666);

            if (m_sem_id == -1)
            {
                LOG_TRACE("semget(open) failed,err=%d", errno);
                return -1;
            }
        }
        else
        {
            //New semaphore created
            union semu { int val; };
            semu arg;
            arg.val = 1;

            if (semctl(m_sem_id, 0, SETVAL, arg) == -1)
            {
                LOG_TRACE("semctl failed, err=%d", errno);
                semctl(m_sem_id, 0, IPC_RMID, NULL);
                m_sem_id = -1;
                return -1;
            }
            return 0;
        }

        return 0;
#endif
}


void CMutex::Lock()
{
#if defined(_WIN32)
        ::WaitForSingleObject(m_hMutex, INFINITE);
#endif
#if defined(_LINUX)
        struct sembuf lock;

        lock.sem_num = 0;
        lock.sem_op = -1;
        lock.sem_flg = SEM_UNDO;

        semop(m_sem_id, &lock, 1);
#endif
}

void CMutex::Unlock()
{
#if defined(_WIN32)
        ::ReleaseMutex(m_hMutex);
#endif
#if defined(_LINUX)
        struct sembuf unlock;

        unlock.sem_num = 0;
        unlock.sem_op = 1;
        unlock.sem_flg = SEM_UNDO;

        semop(m_sem_id, &unlock, 1);
#endif
}

 

posted @ 2012-12-06 15:18  Kingdom_0  阅读(855)  评论(0编辑  收藏  举报