linux共享内存相关

概念

共享内存
共享内存可以说是最高效的进程间通信方式。同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都可以。

临界资源:多个进程看到的同一个资源(公共资源)
临界区:访问临界资源的代码段。
原子操作:操作一旦开始执行,就一定要执行结束,中途不能被任何原因打断,要么全做,要么不做,不能只做一半。

信号量(用来协调进程对共享资源的访问),程序对其访问都是原子操作,且只允许对它进行等待(P)和释放(V)操作。

作用:控制多个进程对临界资源的访问,使程序在同一个时刻,只有一个进程访问临界资源(进行进程间同步控制)。

P(sv):如果信号量sv的值大于零,就给它减1;如果它的值为零,就挂起等待。
V(sv):释放操作,它使信号量变为可用,如有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.

例子:两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,它将得到信号量,并可以进入临界区,使sv减1。而第二个进程将被阻止进入临界区,因为当它试图执行P(sv)时,sv为0,它会被挂起以等待第一个进程离开临界区域并执行V(sv)释放信号量,这时第二个进程就可以恢复执行。
当临界区资源可用时,信号量变量n的值是true(即二进制信号量),然后P(n)操作将它变成false以表示临界区正在被使用;当进程离开临界区时,使用V(n)操作将它加1,置为true,使临界区再次变为可用。

代码

sharedMemory.h

#pragma once
#include <string>
#include <vector>
#include <sys/shm.h>
#include "sem.h"

struct shmData
{
    int status;//状态字段(1为可读,0为不可读)
    char* data;
};

class SharedMemory
{
public:
	SharedMemory();
	SharedMemory(int type);
	~SharedMemory();

	char* createMemory(int size);
	int destoryMemory();
	void shmLock();
	void shmUnLock();

private:
	Sem sem;
	int shmId;
	void* shm;
	int key;
};


sharedMemory.cpp:

#include "sharedMemory.h"

SharedMemory::SharedMemory(int type): key(type), sem(type)
{
}

SharedMemory::~SharedMemory()
{
	cout<< "delete SharedMemory..." <<endl;
}

char* SharedMemory::createMemory(int size) {
    //创建共享内存,指定共享内存名字key,大小size
    shmId = shmget((key_t)key, size, 0666 | IPC_CREAT); 
    CHECK_DO_RTN_VAL(shmId == -1, cout<<"shmget failed\n", nullptr)

    // 将共享内存连接到当前进程的地址空间,返回指向共享内存第一个字节的指针
    shm = shmat(shmId, 0, 0);
    CHECK_DO_RTN_VAL(shm == (void*)-1, cout<<"shmat failed\n", nullptr)

    return (char*)shm;
}

int SharedMemory::destoryMemory() {
    shmdt(shm); //共享内存从当前进程中分离
    shmctl(shmId, IPC_RMID, 0); //删除共享内存
}

void SharedMemory::shmLock() {
    sem.semP();
}
void SharedMemory::shmUnLock() {
    sem.semV();
}

sem.h:

#pragma once
#include <sys/sem.h>
#include <unistd.h>
#include <iostream>
#include <string.h>

#define CHECK_RTN(condition) if(condition){return;}
#define CHECK_DO_RTN(condition, needDo) if(condition){needDo; return;}
#define CHECK_RTN_VAL(condition, val) if(condition){return val;}
#define CHECK_DO_RTN_VAL(condition, needDo, val) if(condition){needDo; return val;}
#define CHECK_DO(condition, needDo) if(condition){needDo;}

using namespace std;

class Sem
{
public:
	Sem(int type);
	~Sem();

	void semP();
	void semV();

private:
	void init();

	int key;
	int semId;

};

union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
};


sem.cpp:

#include "sem.h"

Sem::Sem(int type): key(type + 1)
{
    init();
}

Sem::~Sem()
{
    int rlt = semctl(semId, 0, IPC_RMID); //删除信号量
    CHECK_DO(rlt == -1, cout<<"delete sem failed\n")
}

void Sem::init()
{
	cout<< "semget key" << key << endl;
    semId = semget((key_t)key, 1, IPC_CREAT | 0600);
    CHECK_DO(semId == -1, cout<<"semget failed\n" << strerror(errno))

    union semun initVal;
    initVal.val = 1; //给信号量赋初值1
    int rlt = semctl(semId, 0, SETVAL, initVal);
    CHECK_DO(rlt == -1, cout<<"semctl failed\n"<< strerror(errno))
}

void Sem::semP()
{
    struct sembuf buf;
    buf.sem_num = 0; //信号量下标
    buf.sem_op = -1; //p 减1操作
    buf.sem_flg = SEM_UNDO; //设置在进程出现错误时信号量值自动恢复,防止一个进程占着信号量
    int rlt = semop(semId, &buf, 1); //如果信号量sv的值大于零,就给它减1;如果它的值为零,就挂起等待
    CHECK_DO(rlt == -1, cout<<"semop p failed\n" << strerror(errno))
}

void Sem::semV()
{
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;//v 加1操作
    buf.sem_flg = SEM_UNDO;
    int rlt = semop(semId, &buf, 1);
    CHECK_DO(rlt == -1, cout<<"semop v failed\n")
}

#include "sharedMemory.h"
#include <sys/time.h>

//g++ sharedMemory.cpp sem.cpp write.cpp -o write -std=c++11
//g++ sharedMemory.cpp sem.cpp read.cpp -o read -std=c++11

const int CAMERA = 100001;
const int SIZE = 1920 * 1080;

  uint64_t getSystemClock()
   {
        struct timespec stTime;
        uint64_t ret ;

        clock_gettime(CLOCK_MONOTONIC, &stTime);
        ret = stTime.tv_sec * 1000000 + stTime.tv_nsec / 1000L;
        return ret;
   }

int main() {
	char array[SIZE + 1];
	memset(array, 0, SIZE + 1);
	SharedMemory sharedMemory(CAMERA);
	char* shm = sharedMemory.createMemory(SIZE);

	cout<< "start read app.." <<endl;

	for(int i = 0 ; i < 10000; ++i){
	    	sharedMemory.shmLock();
		memcpy(array, shm, SIZE);
		sharedMemory.shmUnLock();
	}
	cout<< "read time: " << getSystemClock() << endl;

	sharedMemory.destoryMemory();
}

#include "sharedMemory.h"
#include <sys/time.h>

const int CAMERA = 100001;
const int SIZE = 1920 * 1080;

  uint64_t getSystemClock()
   {
        struct timespec stTime;
        uint64_t ret ;

        clock_gettime(CLOCK_MONOTONIC, &stTime);
        ret = stTime.tv_sec * 1000000 + stTime.tv_nsec / 1000L;
        return ret;
   }

int main() {
	char array[SIZE];
	memset(array, 'a', SIZE);
	SharedMemory sharedMemory(CAMERA);
	char* shm = sharedMemory.createMemory(SIZE);

	cout<< "start write app.." <<endl;

	cout<< "write time: " << getSystemClock() << endl;
	for(int i = 0 ;i < 10000; ++i){
		sharedMemory.shmLock();
		memcpy(static_cast<void*>(const_cast<char*>(shm)), array, SIZE);
		sharedMemory.shmUnLock();
	}
	sharedMemory.destoryMemory();
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值