实验目的
了解Linux共享内存(Shared Memory)进行进程通信的基本原理;在Linux上使用C语言编写两个程序,其中一个程序(进程)创建一个共享内存区域,并向该区域写入一些内容,另一个程序(进程)从该共享区域读出内容 ,验证写入的内容与读出的内容是否一致,从而加深对共享内存工作原理的理解。
实验截图
图1 写入程序运行结果
使用 ipcs -m 可以查看系统的共享内存信息,有键值(key),共享内存编号(shmid),拥有者(owner),权限(perms),字节(bytes)等。
图2 查看系统的共享内存
图3 读程序运行结果
从图可看出,写入的内容(name是Chan1-Chan3,age是20-22)与读出的内容是一致的。
程序代码
写入程序:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h> //后面三个头文件是有关共享内存的
#include <sys/shm.h>
#include <sys/types.h>
#define SEGSIZE 4096 //定义共享内存容量
typedef struct{ //读写数据结构体
char name[8];
int age;
} Stu;
int main()
{
int shm_id, i;
char name[8];
Stu *smap;
//获取关键字
//函数原型:key_t ftok(const char *pathname, int proj_id) 成功返回key_t值,失败返回-1
//pathname为路径,必须是真实存在且可以访问的路径。,proj_id是int类型。
key_t key=ftok("/", 1) ;
if (key == -1)
{
perror("ftok error");
return -1;
}
printf("key=%d\n", key);
//创建共享内存
//函数原型:int shmget(key_t key, size_t size, int shmflg); 返回值为shmid,用于连接与分离时传递参数
//key值使用库函数ftok获取,size用于确定共享内存大小,一般是4096的整数倍
// shmflg用于确定共享内存属性。格式为:标志位 | 内存权限
// 0644表示允许一个进程创建的共享内存被内存创建者所拥有的进程向共享内存读取和写入数据,
//同时其他用户创建的进程只能读取共享内存
//IPC_CREAT和IPC_EXCL一起使用,返回新建的共享内存的标识符或者该共享内存已存在,返回-1。
shm_id = shmget(key, SEGSIZE, IPC_CREAT | IPC_EXCL | 0664);
if (shm_id == -1)
{
perror("create shared memory error\n");
return -1;
}
printf("shm_id=%d\n", shm_id);
//将进程与共享内存绑定
//函数原型:void *shmat(int shm_id, const void *shm_addr, int shmflg); 启动对该共享内存的访问
// shm_id是由shmget函数返回的共享内存标识。
// shm_addr指定共享内存连接到当前进程中的地址位置,NULL表示让系统来选择共享内存的地址。
// shm_flg是一组标志位,通常为0
//调用成功时返回一个指向共享内存第一个字节的指针,失败返回-1.
smap = (Stu*)shmat(shm_id, NULL, 0);
memset(name, 0x00, sizeof(name));
strcpy(name, "Chan"); //写入的内容
name[4] = '0';
for (i = 0; i < 3; i++) //写数据
{
name[4] += 1;
strncpy((smap + i)->name, name, 5);
(smap + i)->age = 20 + i;
}
//解除绑定
// 函数原型:int shmdt(const void *shmaddr);
// shmaddr是shmat函数返回的地址指针,调用成功时返回0,失败时返回-1.
if (shmdt(smap) == -1)
{
perror("detach error");
return -1;
}
return 0;
}
读出程序:
#include <stdio.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct{
char name[8];
int age;
} Stu;
int main()
{
int shm_id, i;
key_t key;
Stu *smap;
key = ftok("/", 1); //获取关键字,参数保持一致
if (key == -1)
{
perror("ftok error");
return -1;
}
printf("key=%d\n", key);
//多进程通信时,创建方使用IPC_CREAT | IPC_EXCL,接收方使用0即可
shm_id = shmget(key, 0, 0); //创建共享内存
if (shm_id == -1)
{
perror("shmget error");
return -1;
}
printf("shm_id=%d\n", shm_id);
smap = (Stu*)shmat(shm_id, NULL, 0); //将进程与共享内存绑定
for (i = 0; i < 3; i++) //读数据
{
printf("name:%s\n", (*(smap + i)).name);
printf("age :%d\n", (*(smap + i)).age);
}
if (shmdt(smap) == -1) //解除绑定
{
perror("detach error");
return -1;
}
//删除共享内存
//函数原型:int shmctl(int shm_id, int command, struct shmid_ds *buf);
// shm_id是shmget函数返回的共享内存标识符。
// command是要采取的操作,为IPC_RMID时是删除共享内存,buf可以传NULL
shmctl(shm_id, IPC_RMID, NULL);
return 0;
}