嵌入式操作系统实验——共享内存

一、实验目的

1、了解采用共享内存通信的原理。
2、掌握共享内存的创建及使用方法。

二、实验内容

1、创建写进程,其功能为创建共享内存并映射到当前进程地址空间。接着从标准输入向共享内存中循环写入数据,直至写入“end”后结束退出。
2、读进程使用和写进程相同的key打开共享内存,将共享内存映射到当前进程地址空间,并从共享内存中循环读取数据并输出至终端。
3、通过信号量方式解决读写进程的同步问题。
4、通信完成后,撤销共享内存和进程间的映射,并删除共享内存,删除信号量。

三、实验源程序及结果截图

w.c(写入内存的代码)

#include "shm_com.h"
#include "sem_com.h"
#include<signal.h>
int ignore_signal(void){
   signal(SIGINT,SIG_IGN);
   signal(SIGSTOP,SIG_IGN);
   signal(SIGQUIT,SIG_IGN);
   return 0;
}
int main() {
   //最早使用的是struct shm_buff shm_buff_inst[10];
   struct shm_buff *shm_buff_inst;
   void *shared_add=NULL;
   char buffer[BUFSIZ];
   int i=-1;
   int len=1;/*i和len是用来移动指针的*/
    // 生成KEY
    key_t key = ftok(".", 'c');
   //判断key是否生成成功
    if (key < 0) {
        perror("生成KEY错误");
        exit(-1); 
    }
    ignore_signal();/*防止程序非正式退出*/
    // 定义信号量,用于实现共享内存进程之间的互斥
    int semid = semget(key, 1, 0666|IPC_CREAT);
    if (semid < 0) { 
       perror("创建信号量失败");
       exit(-1);
    }
    // 初始化信号量为1
    init_sem(semid,1);
    // 创建共享内存
    int shmid = shmget(ftok(".",'d'), 10240, 0666|IPC_CREAT);
    if (shmid <0) {
        perror("创建共享内存失败");
        del_sem(semid);
        exit(1);
    }
// 将共享内存地址映射到当前进程地址空间
    shared_add=shmat(shmid,(void *)0, 0);
    if(shared_add==(void*)-1){
        perror("映射出错");
        del_sem(semid);
        exit(1);
   }
    shm_buff_inst=(struct shared_use_at *)shared_add;
    printf("映射地址为 %X\n", (int) shm_buff_inst);
   do{
       sem_p(semid);
        printf("写入共享内存中(当输入end结束):");
        i++;
    /*向内存写入数据*/
   if(fgets((shm_buff_inst+i*len)->buffer,SHM_BUFF_SZ,stdin)==NULL){
      perror("fgets出错");
      sem_v(semid);
      break;
   }
    (shm_buff_inst+i*len)->pid=getpid();//获取进程号
     sem_v(semid);
  }while(strncmp((shm_buff_inst+i*len)->buffer,"end",3)!=0);
  //删除映射
  if(shmdt(shared_add)==1){
    perror("删除映射出错:");
    exit(1);
  }
  exit(0);
}

r.c(读取共享内存的代码)

#include "sem_com.h"
#include "shm_com.h"
int main(){
   void *shared_add=NULL;
   struct shm_buff *shm_buff_inst;//创建了一个结构体指针,存储每次输入的内容的进程号和字符串
   char buffer[BUFSIZ];
   int i=-1;
   int len= 1;
    // 生成KEY
    key_t key = ftok(".", 'c');
    if (key < 0) {
        perror("生成KEY错误");
        exit(-1);
    }
    // 获得信号量
    int semid = semget(key, 1, 0666);
    if (semid < 0) {
        perror("信号量不存在");
        exit(1);
    }
    // 创建共享内存sizeof(struct shm_buff)
    int shmid = shmget(ftok(".", 'd'),10240, 0666 | IPC_CREAT );//共享内存的空间定的是10240
    if (shmid < 0) {
       perror("创建共享内存失败");
        exit(1);
    }
    // 映射共享内存
    shared_add = shmat(shmid, (void *)0, 0);
    if(shared_add==(void*)-1){
       perror("映射出错");
       del_sem(semid);
       exit(1);
    }
    printf("映射地址为 %x\n", (int) shared_add);
    shm_buff_inst=(struct shm_buff *)shared_add;/*出问题的地方*/
   do{
    sem_p(semid);
     i++;
    printf("进程为%d,内容为%s\n",(shm_buff_inst+i*len)->pid,(shm_buff_inst+i*len)->buffer);
   /*向内存读出数据*/
   if(strncmp((shm_buff_inst+i*len)->buffer,"end",3)==0){
    break;
   }
   (shm_buff_inst+i*len)->pid=0;
   memset((shm_buff_inst+i*len)->buffer,0,SHM_BUFF_SZ);
    sem_v(semid);
}while(1);
   //删除映射
   if(shmdt(shared_add)==-1){
     shmdt(shared_add); 
     exit(0);
   }   
   //删除信号量
   del_sem(semid);
   //删除共享内存
   if(shmctl(shmid,IPC_RMID,NULL)==-1){
     perror("删除共享内存失败");
     exit(-1);
    }
    exit(0);
}

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; 
}

shm_com.h

#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#define SHM_BUFF_SZ 2048
struct shm_buff{
int pid;
char buffer[SHM_BUFF_SZ];
};

makefile

makelib: sem_com.o
        gcc sem_com.c -fPIC -shared -o libsem.so
all: makelib
        cp libsem.so /lib
        gcc -o read r.c -L. -lsem
        gcc -o write w.c -L. -lsem

进入文件夹: cd exp6
编译makefile: sudo make all
执行write文件: ./write
执行read文件: ./read
在这里插入图片描述

四、实验问题总结

1.权限不够问题:
在执行makefile时,提示权限不够,linux下有超级用户(root)和普通用户,普通用户不能直接操作没有权限的目录。在命令前加一个sudo即可。
2.共享内存 errno 13 Permission denied
修改key的值即可。
3.共享内存 errno 22 Invalid argument
猜测是由于之前打开的共享内存并没有关闭,重启虚拟机解决了这个问题

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值