Linux进程间通信之互斥锁(共享内存实现),包括C++11的事件,信号量

1、基于共享内存的互斥锁

开辟一块共享内存,使得相关进程均可访问同一块区域,再将互斥锁定义在该区域(即共享内存)上,使得相关进程可以使用该锁。
互斥量保存在共享内存中,在初始化该锁的时候,设置为进程间共享,这样两个进程连接到共享内存后,都可以获得这个互斥锁

参考:
linux不同进程使用共享内存及互斥锁
Linux进程间互斥锁 (共享内存实现)
互相独立进程间共享内存互斥访问的解决办法

2、相关代码

Event.h

#pragma once
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifndef _WIN32
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#else
#include 
#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 
#include  
#include   
#include   
#include  
#include  
#include  
#include  
#include 

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

你可能感兴趣的:(Linux,杂记,Linux,学习,进程锁)