目录
一:案例结果测试
首先内存初始化操作: ipcrm -a
再查看一下内存三剑客 消息队列 共享内存 信号量 已经为初始状态: ipcs
先运行的是写数据,如果只写不读,那么数组会开50个空间 ,不过由于测试的时间太长,这里以写15个数据后开始读操作为例
写15个数据后,开始读数据,也不难看出,每写完15个数据后(读取完15个数据后),会清空数组数据,能够复用 写入 读取数据
同样,我们可以ipcs查看一下内存三剑客 目前状态
可以看到消息17条【本次测试在17条数据写入读取后 结束了程序的运行】
由此完成了 共享内存 + 消息队列 + 信号量 的联合使用,前置服务器和后置服务器之间的数据交互使用到的就是内存三剑客
二:案例完整代码
#include<iostream>
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include<unistd.h>
#include<string.h>
//数据块大小
#define BLOCKNUM 50
using namespace std;
union semun {
int val; /* Value for SETVAL */
struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short* array; /* Array for GETALL, SETALL */
struct seminfo* __buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
typedef struct msgsendbuf {
long mtype; /* message type, must be > 0 */
char mtext[2]; /* message data */
}MSGBUF;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
//信号量的创建
int sem_create(key_t key, int num_sems)
{
int res = 0;
res = semget(key, num_sems, IPC_CREAT | 0777);
if (res < 0)
{
perror("semget error");
}
return res;
}
//信号量赋初始值
int sem_setVal(int semid, int semindex, int val)
{
union semun arg;
arg.val = val;
int res = semctl(semid, semindex, SETVAL, arg);
if (res < 0)
{
perror("semctl error");
}
return res;
}
//信号量 P操作 -1
int sem_p(int sem_id, int semindex)
{
struct sembuf buf = { semindex,-1,SEM_UNDO };
int res = semop(sem_id, &buf, 1);
if (res < 0)
{
perror("semop error");
}
return res;
}
//信号量 V操作 +1
int sem_v(int sem_id, int semindex)
{
struct sembuf buf = { semindex,1,SEM_UNDO };
int res = semop(sem_id, &buf, 1);
if (res < 0)
{
perror("semop error");
}
return res;
}
int main()
{
void* shmaddr; //共享内存首地址
int shmid = 0; //共享内存id
int msgid = 0; //消息队列id
MSGBUF sendbuf = { 0 }; //消息队列发送信息的结构体
int semid = 0; //信号量id
int arr[BLOCKNUM] = { 0 }; //数组
int index = 0; //数组下标
int num = 1;
STU stu1 = { "","陈茹涵"};
//共享内存创建
shmid = shmget((key_t)1001, sizeof(arr) + sizeof(STU) * BLOCKNUM, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmid error");
}
//消息队列
msgid = msgget((key_t)1002, IPC_CREAT | 0777);
if(msgid < 0)
{
perror("msgid error");
}
//信号量创建
semid = sem_create((key_t)1003, 1);
if (semid < 0)
{
perror("sem_create error");
}
else
{
//信号量0下标设置初始值1
sem_setVal(semid, 0, 1);
}
while (1)
{
cout << "------------------准备工作完成 开始写数据--------------------" << endl;
//进程加锁
sem_p(semid, 0);
//操作共享内存先连接 获取共享内存首地址
shmaddr = shmat(shmid, NULL, 0);
//读索引区
memcpy(arr, shmaddr, sizeof(arr));
for (int i = 0; i < BLOCKNUM; i++)
{
if (arr[i] == 0)
{
index = i;
break;
}
}
cout << "找到可以写数据的下标 index =" << index << endl;
sprintf(stu1.stuid, "OMO22030%d", num);
//1 写数据区
memcpy((void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), &stu1, sizeof(STU));
//2 写索引区
arr[index] = 1;
memcpy((void*)(shmaddr + index * sizeof(int)), &arr[index], sizeof(int));
//共享内存的断开连接
shmdt(shmaddr);
//进程解锁
sem_v(semid, 0);
cout << "共享内存写入成功" << endl;
//消息队列通知后置服务器
sendbuf.mtype = 1;
sprintf(sendbuf.mtext, "%d", index);
if (msgsnd(msgid, &sendbuf, sizeof(sendbuf), 0) == -1)
{
perror("msgsnd error");
}
cout << "消息队列发送成功" << endl;
index = 0;
bzero(&sendbuf, sizeof(sendbuf));
bzero(&arr, sizeof(arr));
num++;
sleep(1);
}
return 0;
}
#include<iostream>
#include<stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#include <sys/msg.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
//数据块大小
#define BLOCKNUM 50
using namespace std;
union semun {
int val; /* Value for SETVAL */
struct semid_ds* buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short* array; /* Array for GETALL, SETALL */
struct seminfo* __buf; /* Buffer for IPC_INFO
(Linux-specific) */
};
typedef struct msgsendbuf {
long mtype; /* message type, must be > 0 */
char mtext[2]; /* message data */
}MSGBUF;
typedef struct student
{
char stuid[20];
char stuname[20];
}STU;
//信号量的创建
int sem_create(key_t key, int num_sems)
{
int res = 0;
res = semget(key, num_sems, IPC_CREAT | 0777);
if (res < 0)
{
perror("semget error");
}
return res;
}
//信号量 P操作 -1
int sem_p(int sem_id, int semindex)
{
struct sembuf buf = { semindex,-1,SEM_UNDO };
int res = semop(sem_id, &buf, 1);
if (res < 0)
{
perror("semop error");
}
return res;
}
//信号量 V操作 +1
int sem_v(int sem_id, int semindex)
{
struct sembuf buf = { semindex,1,SEM_UNDO };
int res = semop(sem_id, &buf, 1);
if (res < 0)
{
perror("semop error");
}
return res;
}
int main()
{
void* shmaddr; //共享内存首地址
int shmid = 0; //共享内存id
int msgid = 0; //消息队列id
MSGBUF rcvbuf = { 0 }; //消息队列接收信息的结构体
int semid = 0; //信号量id
int arr[BLOCKNUM] = { 0 }; //数组
int index = 0; //数组下标
STU resstu = { 0 };
//共享内存创建
shmid = shmget((key_t)1001, sizeof(arr) + sizeof(STU) * BLOCKNUM, IPC_CREAT | 0777);
if (shmid < 0)
{
perror("shmid error");
}
//消息队列
msgid = msgget((key_t)1002, IPC_CREAT | 0777);
if (msgid < 0)
{
perror("msgid error");
}
//信号量创建
semid = sem_create((key_t)1003, 1);
if (semid < 0)
{
perror("sem_create error");
}
while (1)
{
cout << "------------------准备工作完成 开始读数据--------------------" << endl;
if (msgrcv(msgid, &rcvbuf, sizeof(rcvbuf), 1, 0) == -1)
{
perror("msgrcv error");
}
else
{
index = atoi(rcvbuf.mtext);
cout << "读到的数据的下标 index =" << index << endl;
sem_p(semid, 0);
shmaddr = shmat(shmid, NULL, 0);
//1 先读索引区 index下标的位置
memcpy(&arr[index], (void*)(shmaddr + index * sizeof(int)), sizeof(int));
//判断是否为1 为1 表示可以读取
if (arr[index] == 1)
{
//2 读取数据区数据
memcpy(&resstu, (void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), sizeof(STU));
//3 清空数据区
memset((void*)(shmaddr + sizeof(arr) + index * sizeof(STU)), 0, sizeof(STU));
//4 索引区 对应下标位置修改0 这里操作arr是进程中的数组,并不是共享内存的数组
//因此 再写入一次共享内存索引区
arr[index] = 0;
memcpy((void*)(shmaddr + sizeof(int) * index), &arr[index], sizeof(int));
cout << "读到的数据 resstu.stuid = " << resstu.stuid << endl;
cout << "读到的数据 resstu.stuname = " << resstu.stuname << endl;
cout << "读数据完成" << endl;
}
shmdt(shmaddr);
sem_v(semid, 0);
}
index = 0;
bzero(&rcvbuf, sizeof(rcvbuf));
bzero(&arr, sizeof(arr));
sleep(1);
}
return 0;
}