Linux 互斥量Mutex 进程间共享

6 篇文章 0 订阅

        Mutex 本身是支持进程内和进程间两种类型的,平时在使用的时候用到的最多的还是进程内同步,昨天在看android framework的时候,发现其在barrier上还是使用了Mutex的进程间同步。实现方式还是蛮简单的,将pthread_mutex_t数据结构保存到共享内存上,从而实现多个进程共享同一内存,不像windows上指定一个名字就搞定了,废话少说,上代码:

//Mutex.h
#ifndef CXX_MUTEX_H
#define CXX_MUTEX_H

#include <pthread.h>
#include <string>
using std::string;


class Mutex {
public:
    enum {
        MUTEX_PRIVATE = 0,  //process private
        MUTEX_SHARE   = 1   //process shared
    };

    /**
     * Constructor
     * @param type: MUTEX_PRIVATE or MUTEX_SHARE
     * @param name: if type=MUTEX_SHARE, name must be not null .
     */
    Mutex(int type, const char* name);

    ~Mutex();

    int  type() const;

    /**
     * @warnning:
     *     if Mutex is shared in process, the process which create mutex must call this function
     */
    bool init();

    /**
     * @warnning:
    *      If Mutex is shared in process, the process which create mutex must call this function
     */
    bool destroy();

    bool lock();

    bool unlock();

    bool trylock();

private:
    bool  createDir(const char* dir);
    bool  write(int fd, const char* buff, int len);
    bool  saveShareMutexToFile();

private:
    int             m_type;
    int             m_fd;
    string          m_name;
    pthread_mutex_t* m_mutex;
};
#endif

//Mutex.cpp
#include "Mutex.h"
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#define DBG_MSG(fmt, ...)   printf(fmt, ##__VA_ARGS__)

static const char* s_MutexDir = "/tmp/mutex/";
static const char* s_MutexSuffix = ".process.mutex";

 Mutex::Mutex(int type, const char* name)
    : m_type(type)
    , m_fd(-1)
    , m_mutex(NULL)
 {

    if (MUTEX_PRIVATE == m_type) {
        m_mutex = new pthread_mutex_t();
        pthread_mutex_init(m_mutex, NULL);
    }
    else {

        if (NULL == name) {
            name = "default";
        }

        createDir(s_MutexDir);

        m_name = s_MutexDir;
        m_name += name;
        m_name += s_MutexSuffix;
    }
 }

 Mutex::~Mutex()
 {
    if ((NULL != m_mutex) && (MUTEX_PRIVATE == m_type)) {
        pthread_mutex_destroy(m_mutex);
        delete m_mutex;
        m_mutex = NULL;
    }

    if (MUTEX_SHARE == m_type) {

        if (NULL != m_mutex) {
            munmap(m_mutex, sizeof(pthread_mutex_t));
            m_mutex = NULL;
        }

        if (-1  != m_fd) {
            close(m_fd);
            m_fd = -1;
        }

    }//if
 }


int  Mutex::type() const
{
    return m_type;
}

bool Mutex::init()
{
    if(MUTEX_SHARE == m_type) {

        if (0 != access(m_name.c_str(), F_OK) != 0) {
            saveShareMutexToFile();
        }

        //open file and create shm
        m_fd = open(m_name.c_str(), O_RDWR);
        if (m_fd == -1) {
            DBG_MSG("%s %d: error=%d\n", __FILE__, __LINE__, errno);
            return false;
        }

        m_mutex = (pthread_mutex_t*)mmap(NULL, sizeof(pthread_mutex_t), PROT_READ|PROT_WRITE, MAP_SHAREDr, m_fd, 0);
        if (-1l == (long)m_mutex) {
            DBG_MSG("%s %d: error=%d\n", __FILE__, __LINE__, errno);
            return false;
        }
    }

    return true;
}

bool Mutex::destroy()
{
    if(NULL != m_mutex) {
        pthread_mutex_destroy(m_mutex);
    }
}

bool Mutex::lock()
{
    if (NULL == m_mutex) {
        DBG_MSG("%s %d: m_mutex is null \n", __FILE__, __LINE__);
        return false;
    }

    return (0 == pthread_mutex_lock(m_mutex));
}

bool Mutex::unlock()
{
    if (NULL == m_mutex) {
        DBG_MSG("%s %d: m_mutex is null \n", __FILE__, __LINE__);
        return false;
    }

    return (0 == pthread_mutex_unlock(m_mutex));
}

bool Mutex::trylock()
{
    if (NULL == m_mutex) {
        DBG_MSG("%s %d: m_mutex is null \n", __FILE__, __LINE__);
        return false;
    }

    return (0 == pthread_mutex_trylock(m_mutex));
}

bool Mutex::createDir(const char* dir)
{
    if(NULL == dir) {
        return false;
    }

    if (0 != access(s_MutexDir, F_OK)) {
        string cmd = "mkdir -p ";
        cmd += dir;

        system(cmd.c_str());
    }

    return true;
}

bool Mutex::write(int fd, const char* buff, int len)
{
    int writeNum = 0;

    while((len - writeNum) > 0) {
        writeNum += ::write(fd, buff + writeNum, len - writeNum);
    }

    return true;
}

bool Mutex::saveShareMutexToFile()
{
     //write data to file
    pthread_mutexattr_t mutexattr;
    pthread_mutex_t mutex;
    pthread_mutexattr_init(&mutexattr);
    pthread_mutexattr_setpshared(&mutexattr,PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(&mutex, &mutexattr);
    int fd = open(m_name.c_str(), O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    write(fd, (const char*)&mutex, sizeof(pthread_mutex_t));
    close(fd);
    pthread_mutex_destroy(&mutex);
}


推荐使用方式:通常一个系统是由多个process组成的,其中根据其角色又分为前期初始化、事务处理、后期清理。建议在前期初始化的时候讲所有的用于进程间共享的Mutex前部初始化(init),在系统后期清理掉时候再将所有的共享Mutex销毁(destroy)。

Mutex用于进程间互斥,杀伤力比较大,一个进程出问题了导致锁没有释放,结果其他进程也会受到波及,建议尽量不要使用Mutex用做进程间互斥!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值