Linux-C 共享内存 03.23
进程间通信IPC(共享内存) 03.23
IPC六种技术:
–(1)管道(pipe)和命名管道(FIFO ---- 最大传输容量65535byte;文件容易被误删;
–(2)信号(signal)
–(3)消息队列 -----消息队列也有管道一样的不足,就是每个数据块的最大长度是有上限的
–(4)共享内存
–(5)信号量
–(6)套接字(socket)网络
~# ipcs ----查询共享内存
~#ipcrm -h
~#ipcrm -m (shmid)
~#ipcrm -a 删除所有用户所开的共享内存
共享内存,内存不属于任何进程和程序,只属于系统
shmget()
功能:创建共享内存
返回:如果共享内存创建成功,*shmget将返回一个非负整数,即该段共享内存的标识码;如果失败,则返回-1
int shmget(key_t key,size_t size, int shmflg);
//key: 这个共享内存段的名字,如果key不存在则创建,存在则不做任何操作
//size: 需要共享的内存量
//shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的(九个模式mode----0777-----可读可写可执行)
shmat()
功能:共享内存段刚被创建的时候,任何进程还都不能访问它,为了建立对这个共享内存段的访问渠道,必须使用shmat把该共享内存连接到某个进程的地址空间。
返回:成功,返回一个指针,指针指向共享内存的第一个字节;失败,则返回 -1
void* shmat(int shm_id,const void *shm_addr,int shmflg);
//shm_id: shmget返回的共享内存标识
//shm_addr:把共享内存连接到当前进程去的时候准备放置它的那个地址
//shmflg:是一组按位or(或)在一起的标志。它的两个可能取值是SHM_RND和SHM_RDONLY
•shm_addr==0:核心自动选择一个地址
•shm_addr!=0&&shmflg!=SHM_RND : 以shmaddr为连接地址。
•shm_addr!=0&&shmflg设==SHM_RND : 连接的地址会自动向下调整为SHMLBA的整数倍。公式: shm_addr- (shm_addr% SHMLBA)
•shmflg==SHM_RDONLY : 表示连接操作用来只读共享内存
•在fork() 后,子进程继承已连接的共享内存
•在exec()或结束进程后,已连接的共享内存会自动脱离(detach)
shmdt()
功能:把共享内存与当前进程脱离开
返回:操作成功,返回0,失败则返回 -1
注意:脱离共享内存并不等于删除它,只是当前进程不能再继续访问它而已
int shmdt(const void *shm_addr);
//shm_addr: 由shmat返回的地址指针
shmctl函数 — 少用,数据直接覆盖就可以了



WMain.cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
typedef struct stu
{
char stuid[10];
char name[20];
}STU;
int main()//写段
{
int shmid = 0;
void *shmaddr;
STU stu1 = { "OMO210815","wubingtu" };
shmid = shmget((key_t)1001, 2048, IPC_CREAT|0777);//0777---对象不是文件,不需要使用umask()
if (shmid == -1)
{
perror("shmget error:");
}
else
{
//连接共享内存,获取共享内存的首地址
shmaddr=shmat(shmid,NULL,0 );//第二个参数---共享内存的地址
//写入数据--内存拷贝
//void *memcpy(void *dest, const void *src, size_t n);
memcpy(shmaddr,&stu1,sizeof(STU));
}
return 0;
}
RMain.cpp
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
using namespace std;
typedef struct stu
{
char stuid[10];
char name[20];
}STU;
int main()
{
int shmid = 0;
void* shmaddr;
STU resstu={0};
shmid = shmget((key_t)1001, 2048, IPC_CREAT | 0777);//0777不是文件,不用使用umask()
if (shmid == -1)
{
perror("shmget error:");
}
else
{
//连接共享内存,获取共享内存的首地址
shmaddr = shmat(shmid, NULL, 0);//第二个参数---共享内存的地址
//写入数据--内存拷贝
//void *memcpy(void *dest, const void *src, size_t n);
memcpy(&resstu, shmaddr, sizeof(STU));
cout << resstu.stuid <<" " << resstu.name << endl;
//memset(shmid,0,sizeof(shmid)); bzero
shmdt(shmaddr);
}
}
作业一:
1.模仿课堂案例,使用共享内存完成要求如下:
1)定义聊天结构体,结构如下
struct chat
{
char uid[10];
char msg[50];
}
2)A程序和B程序两个工程,两个工程存在同样的结构体,用户名可以定死
3)程序运行A程序可以向B程序发送消息,msg消息通过控制台输入
4)B程序也可以向A程序发送消息,步骤同上
5)A和B都可以看到对方发送的消息如 “[用户名]对我说:xxx”的信息
自己的方案,有逻辑上的BUG
A point
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include <unistd.h>
using namespace std;
typedef struct chat
{
char uid[20];
char msg[100];
}chat;
int main()
{
int shmid_a2b = 0;
int shmid_b2a = 0;
void* shmaddr_a2b;
void* shmaddr_b2a;
chat a={ "machineA" };
chat b;
shmid_a2b = shmget((key_t)1001, 2048, IPC_CREAT | 0777);
shmid_b2a = shmget((key_t)1002, 2048, IPC_CREAT | 0777);
if (shmid_a2b == -1|| shmid_b2a == -1)
{
perror("shmget error:");
}
else
{
while (1)
{
bzero(a.msg, sizeof(a.msg));
bzero(b.msg, sizeof(b.msg));
cout << "A2B" << endl;
fgets(a.msg, sizeof(a.msg), stdin);
shmaddr_a2b = shmat(shmid_a2b, NULL, 0);
memcpy(shmaddr_a2b, &a, sizeof(chat));
sleep(5);
shmaddr_b2a = shmat(shmid_b2a, NULL, 0);
memcpy(&b, shmaddr_b2a, sizeof(chat));
if (strlen(b.msg) != 0)
{
cout << b.uid << " say: " << b.msg ;
memset(b.msg, 0, sizeof(b.msg));
}
}
}
shmdt(shmaddr_a2b);
shmdt(shmaddr_b2a);
return 0;
}
B point
#include <sys/ipc.h>
#include <sys/shm.h>
#include<string.h>
#include<stdio.h>
#include<iostream>
#include <unistd.h>
using namespace std;
typedef struct chat
{
char uid[20];
char msg[100];
}chat;
int main()
{
int shmid_a2b = 0;
int shmid_b2a = 0;
void* shmaddr_a2b;
void* shmaddr_b2a;
chat b = { "machineB" };
chat a;
shmid_a2b = shmget((key_t)1001, 2048, IPC_CREAT | 0777);
shmid_b2a = shmget((key_t)1002, 2048, IPC_CREAT | 0777);
if (shmid_a2b == -1 || shmid_b2a == -1)
{
perror("shmget error:");
}
else
{
while (1)
{
bzero(b.msg, sizeof(b.msg));
bzero(a.msg, sizeof(a.msg));
cout << "B2A" << endl;
shmaddr_a2b = shmat(shmid_a2b, NULL, 0);
memcpy(&a, shmaddr_a2b, sizeof(chat));
if (strlen(a.msg) != 0)
{
cout << a.uid << " say: " << a.msg ;
memset(a.msg, 0, sizeof(a.msg));
}
sleep(5);
fgets(b.msg, sizeof(b.msg), stdin);
shmaddr_b2a = shmat(shmid_b2a, NULL, 0);
memcpy(shmaddr_b2a, &b, sizeof(chat));
}
}
shmdt(shmaddr_a2b);
shmdt(shmaddr_b2a);
return 0;
}
进阶版(消息队列+共享内存 方案)
A point
B point
更多推荐



所有评论(0)