1、基于共享内存的互斥锁
开辟一块共享内存,使得相关进程均可访问同一块区域,再将互斥锁定义在该区域(即共享内存)上,使得相关进程可以使用该锁。
互斥量保存在共享内存中,在初始化该锁的时候,设置为进程间共享,这样两个进程连接到共享内存后,都可以获得这个互斥锁
参考:
linux不同进程使用共享内存及互斥锁
Linux进程间互斥锁 (共享内存实现)
互相独立进程间共享内存互斥访问的解决办法
2、相关代码
Event.h
#pragma once
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <string>
#include <memory>
#include <stdio.h>
#include <iostream>
#include <pthread.h>
#ifndef _WIN32
#include <unistd.h>
#include <semaphore.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/shm.h>
#else
#include <Windows.h>
#endif
using namespace std;
//事件
class Event
{ // No signal when init
public:
void Wait()
{
std::unique_lock<std::mutex> lker(m_mtx);
m_cv.wait(lker);
}
bool Wait(int nMillSec)
{
std::chrono::milliseconds mills(nMillSec);
std::unique_lock<std::mutex> lker(m_mtx);
auto ret = m_cv.wait_for(lker, mills);
return (ret != std::cv_status::timeout);
}
void NotifyOne()
{
m_cv.notify_one();
}
void NotifyAll()
{
m_cv.notify_all();
}
private:
std::mutex m_mtx;
std::condition_variable m_cv;
};
//信号量
class Semaphore
{
public:
Semaphore(int nCount = 0) :m_count(nCount) {}
void Wait()
{
std::unique_lock<std::mutex> lker(m_mtx);
m_cv.wait(lker, [this]() {return m_count > 0; });
--m_count;
}
void Signal()
{
{
std::unique_lock<std::mutex> lker(m_mtx);
++m_count;
} // 通知前解锁,避免获取信号后因得不到锁重新进入等待
m_cv.notify_one();
}
private:
int m_count;
std::mutex m_mtx;
std::condition_variable m_cv;
};
//共享内存进程锁
class name_mutex
{
public:
name_mutex(string name, int id)
{
#ifndef _WIN32
m_cMutexName = name;
key_t shmKey = ftok(m_cMutexName.c_str(), id);//创建IPC对象的键值key,即共享内存的键值
size_t MAPPING_SIZE = 512;
//IPC_CREAT: 如果 key 对应的共享内存不存在,则创建之 ;
//IPC_EXCL: 如果该 key 对应的共享内存已存在,则报错
if((m_mfd = shmget(shmKey, MAPPING_SIZE, IPC_CREAT|IPC_EXCL|0666)) == -1)//成功返回共享内存的ID,失败返回-1
{
//无IPC_xxx标识表示引用已存在的共享内存,mode为0表示无权限检查。所以shmflag为0表示不做权限检查,打开已经存在的共享内存
m_mfd = shmget(shmKey, MAPPING_SIZE, 0) ;//最后一个参数为0表示取共享内存标识符
}
//printf("Class Mutex: shmget OK, devName=%s, id=%d, mfd=%d, pMutex=%x, shmKey=%x\n",m_cMutexName.c_str(),id,m_mfd,m_pMutex,shmKey);
if(m_mfd == -1)
m_pMutex = NULL;
else
{
m_pMutex = (pthread_mutex_t*)shmat(m_mfd , NULL , 0);//对共享内存进行映射,如果成功,返回共享内存基地址,出错返回-1
//将共享内存的首地址作为互斥锁,并设置锁的属性为进程间共享
pthread_mutexattr_t mutex_attr;
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE_NP);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(m_pMutex, &mutex_attr);
}
#else
m_cMutexName = name+to_string(id);
m_pMutex = CreateMutex(NULL, FALSE, m_cMutexName.c_str());
#endif
if (m_pMutex == NULL)
{
//printf("CreateMutex Name=%s(%d) ERROR\n", m_cMutexName.c_str(),id);
}
else
{
// printf("CreateMutex Name=%s(%d) OK\n", m_cMutexName.c_str(),id);
}
}
~name_mutex()
{
#ifndef _WIN32
if(m_pMutex == NULL)
return ;
pthread_mutex_destroy(m_pMutex);
//当使用 IPC_RMID 后
//SHM 并不会被真正删除,要等到 shm_nattch 等于 0 时才会被真正 删除。IPC_RMID 只是为删除做准备,而不是立即删除。
shmdt(m_pMutex);//解除共享内存的映射,
shmid_ds ds_buf;
shmctl(m_mfd, IPC_STAT, &ds_buf);//获取属性信息,放置到 buf 中
//printf("Class name_mutex: ~name_mutex: nattach=%d, mfd=%d\n",ds_buf.shm_nattch,mfd);
if(ds_buf.shm_nattch == 0)
{
shmctl(m_mfd, IPC_RMID , NULL);//将共享内存标记为“即将被删除”状态
//printf("Class name_mutex: ~name_mutex OK: mfd=%d\n",mfd);
}
m_pMutex = NULL ;
#else
CloseHandle(m_pMutex);
#endif
}
void lock()
{
#ifndef _WIN32
pthread_mutex_lock(m_pMutex);
#else
WaitForSingleObject(m_pMutex, INFINITE);
#endif
}
void unlock()
{
#ifndef _WIN32
pthread_mutex_unlock(m_pMutex);
#else
ReleaseMutex(m_pMutex);
#endif
}
int trylock(unsigned int times)
{
int ret = -1;
#ifndef _WIN32
for(int i=0; i<times; i++)
{
ret = pthread_mutex_trylock(m_pMutex);
if(ret == 0) break;
usleep(500);
}
#else
ret = WaitForSingleObject(m_pMutex, times);
#endif
return ret;
}
#ifndef _WIN32
pthread_mutex_t *m_pMutex;
int m_mfd;
#else
void* m_pMutex;
#endif
private:
string m_cMutexName;
};
class name_lock
{
public:
name_lock(shared_ptr<name_mutex> mtx)//构造函数
{
m_mtx = mtx;
m_mtx->lock();
}
~name_lock()//析构函数
{
m_mtx->unlock();
}
private:
shared_ptr<name_mutex> m_mtx;
};
main.cpp
#include "Event.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
shared_ptr<name_mutex> m_mtxDevice;
m_mtxDevice.reset(new name_mutex("MUTEX",1));//用共享指针对new出来的这个对象进行管理
while(true)
{
{
name_lock lg(m_mtxDevice);//加锁
do something.... //开多个进程,访问同一个资源,而不会有问题
}
}
}
编译:
g++ -std=gnu++11 main.cpp -lpthread