共享内存
- 共享内存是进程间通信的最快方式。
- 在物理内存上开辟一块内存空间,多个进程可以将同一块物理内存空间映射到自己的虚拟空间中,再通过自己的虚拟地址直接访问此空间,通过此方式实现数据的共享。
- 不会随着进程的退出而释放,需要开发人员手动释放。
共享内存的操作流程:
- 创建共享内存空间 ---- 在物理内存上开辟空间。
- 进程将共享内存映射到自己的虚拟地址空间。
- 对共享内存进行操作。
- 不使用则解除进程虚拟内存和共享内存的联系。
- 释放共享内存。
查看共享内存
删除共享内存
ipcrm -m <shmid>
示例
write.cpp
/*
* write a random number between 0 and 999 to the shm
*/
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <error.h>
#include <sys/sem.h>
using namespace std;
int main()
{
int shm_id;
int write_sem_id;
int read_sem_id;
int *share = nullptr;
int num;
int key = 0x123456;
int write_key = 0x111;
int read_key = 0x222;
srand(time(nullptr)); // 初始化随机数的发生器
// 创建并打开信号量
write_sem_id = semget(write_key, 1, IPC_CREAT | 0666);
read_sem_id = semget(read_key, 1, IPC_CREAT | 0666);
// 设置信号量初始值为0
semctl(write_sem_id, 0, SETVAL, 0);
semctl(read_sem_id, 0, SETVAL, 0);
// 创建共享内存 需要指定读写权限
cout << "page size: " << getpagesize() << endl;
shm_id = shmget (key, getpagesize(), IPC_CREAT | 0666);
if(shm_id == -1)
{
perror("shmget error!");
return -1;
}
// 添加对共享内存的映射 attch
share = (int *)shmat(shm_id, nullptr, 0);
int cnt = 5;
struct sembuf v = {0, 1, SEM_UNDO};
struct sembuf p = {0, -1, SEM_UNDO};
while(cnt--)
{
num = random() % 1000;
*share = num;
printf("write a random number %d\n", num);
// V(signal())生产者完成生产
semop(write_sem_id, &v, 1);
// P(wait())等待消费者消费
cout << "等待消费者完成消费" << endl;
auto ret = semop(read_sem_id, &p, 1);
if(ret != 0)
{
perror("semop read_sem_id error!");
}
cout << "消费者已完成消费" << endl;
}
// 删除对共享内存的映射 detach
if(0 != shmdt(share))
{
cout << "detach share mem fail!" << endl;
}
return 0;
}
read.cpp
/*
* read from the shm every 2 second
*/
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <error.h>
#include <sys/sem.h>
using namespace std;
int main()
{
int shm_id;
int *share;
int key = 0x123456;
int write_key = 0x111;
int read_key = 0x222;
int write_sem_id;
int read_sem_id;
// 创建并打开信号量
write_sem_id = semget(write_key, 1, IPC_CREAT | 0666);
read_sem_id = semget(read_key, 1, IPC_CREAT | 0666);
// 设置信号量初始值为0
semctl(write_sem_id, 0, SETVAL, 0);
semctl(read_sem_id, 0, SETVAL, 0);
shm_id = shmget (key, getpagesize(), IPC_CREAT | 0666);
if(shm_id == -1)
{
perror("shmget()");
return -1;
}
share = (int *)shmat(shm_id, 0, 0);
int cnt = 5;
struct sembuf sops;
while(cnt--)
{
// P(wait())等待生产者完成生产
cout << "等待生产者完成生产" << endl;
sops.sem_num = 0;
sops.sem_op = -1; // -1
semop(write_sem_id, &sops, 1);
cout << "生产者已完成生产" << endl;
printf("%d\n", *share);
// V(signal())消费者完成消费
sops.sem_num = 0;
sops.sem_op = 1; // +1
semop(read_sem_id, &sops, 1);
sleep(2);
}
// 删除对共享内存的映射 detach
if(0 != shmdt(share))
{
cout << "detach share mem fail!" << endl;
}
// 删除共享内存
if(0 != shmctl(shm_id, IPC_RMID, nullptr))
{
perror("shmctl RMID fail!");
}
// 删除信号量
if(0 != semctl(write_sem_id, 0, IPC_RMID))
{
perror("semctl rm write_sem_id fail!");
}
if(0 != semctl(read_sem_id, 0, IPC_RMID))
{
perror("semctl rm read_sem_id fail!");
}
return 0;
}
运行结果:
源码获取