一、实验目的
1、了解采用共享内存通信的原理;
2、掌握共享内存的创建及使用方法。
二、实验内容
1、创建写进程,其功能为创建共享内存并映射到当前进程地址空间,然后向内存写入数据,直至遇到’#’为止;
2、读进程使用和写进程相同的KEY创建共享内存并映射到进程地址空间,然后从内存读数据并打印在终端上;
3、注意通过一定的方式来实现读写进程之间的同步。
三、源程序
shm_write.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include"sem_com.h"
#define PATHNAME "."
#define PROJ_ID 0x66
int main() {
// 生成KEY
key_t key = ftok(PATHNAME, PROJ_ID);
if (key < 0) {
perror("生成KEY错误");
exit(-1);
}
// 创建信号量
int semId = semget(key, 1, IPC_CREAT);
if (semId < 0) {
perror("创建信号量失败");
exit(-1);
}
// 初始化信号量
init_sem(semId, 1);
// 创建共享内存
int shmId = shmget(key, 6666, IPC_CREAT);
if (shmId < 0) {
perror("创建共享内存失败");
exit(-1);
}
// 映射共享内存
char *addr = shmat(shmId, NULL, 0);
sleep(1);
int i = 0;
while (1) {
// P操作
sem_p(semId);
printf("write> ");
char c = getchar();
getchar();
addr[i] = c;
i++;
addr[i] = 0;
sleep(1);
// V操作
sem_v(semId);
if (c == '#') {
break;
}
}
//解除共享内存映射
shmdt(addr);
sleep(2);
return 0;
}
shm_read.c:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include"sem_com.h"
#define PATHNAME "."
#define PROJ_ID 0x66
// 原型声明
int indexOf(char *str1, char *str2);
int main() {
// 生成KEY
key_t key = ftok(PATHNAME, PROJ_ID);
if (key < 0) {
perror("生成KEY错误");
exit(-1);
}
// 创建信号量
int semId = semget(key, 1, 0666 | IPC_CREAT | IPC_EXCL);
if (semId < 0) {
perror("创建信号量失败");
exit(-1);
}
// 创建共享内存
int shmId = shmget(key, 6666, 0666 | IPC_CREAT | IPC_EXCL);
if (shmId < 0) {
perror("创建共享内存失败");
exit(-1);
}
// 映射共享内存
char *addr = (char *) shmat(shmId, NULL, 0);
sleep(5);
int index = -1;
while (1) {
// P操作
sem_p(semId);
printf("read> %s\n", addr);
sleep(1);
// V操作
sem_v(semId);
if ((index = indexOf(addr, "#")) != -1) {
break;
}
}
// 解除共享内存映射
shmdt(addr);
sleep(2);
// 删除信号量
del_sem(semId);
// 删除共享内存
if (shmctl(shmId, IPC_RMID, NULL) < 0) {
perror("删除共享内存失败");
exit(-1);
}
return 0;
}
int indexOf(char *str1, char *str2) {
char *p = str1;
int i = 0;
p = strstr(str1, str2);
if (p == NULL)
return -1;
else {
while (str1 != p) {
str1++;
i++;
}
}
return i;
}
sem_com.h:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
#include<unistd.h>
int init_sem(int sem_id, int init_value);
int del_sem(int sem_id);
int sem_p(int sem_id);
int sem_v(int sem_id);
sem_com.c:
#include"sem_com.h"
union semun
{
int val;
struct semid_ds *buf;
unsigned short *array;
};
/*信号量初始化*/
int init_sem(int sem_id, int init_value)
{
union semun sem_union;
sem_union.val = init_value;
if (semctl(sem_id, 0, SETVAL, sem_union) < 0)
{
printf("init_sem");
return -1;
}
return 0;
}
/*从系统中删除信号量*/
int del_sem(int sem_id)
{
union semun sem_union;
if (semctl(sem_id, 0, IPC_RMID, sem_union) < 0)
{
printf("del_sem");
return -1;
}
return 0;
}
/*P操作*/
int sem_p(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = -1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) < 0)
{
printf("sem_p");
return -1;
}
return 0;
}
/*V操作*/
int sem_v(int sem_id)
{
struct sembuf sem_b;
sem_b.sem_num = 0;
sem_b.sem_op = 1;
sem_b.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_b, 1) < 0)
{
printf("sem_v");
return -1;
}
return 0;
}
makefile:
makelib: sem_com.o
gcc sem_com.c -fPIC -shared -o libsem.so
shm: makelib
cp libsem.so /lib
gcc -o read shm_read.c -L. -lsem
gcc -o write shm_write.c -L. -lsem
四、实验步骤、结果截图
(1)使用make工具编译源程序;
(2)测试运行,先运行read,再运行write。输入字符串,测试程序是否正确。
运行结果如下:
运行read的窗口:
运行write的窗口: