两个进程共享内存,一个写,一个读

要求是:生产者进程生成Catalan序列,并将其写入到内存共享对象。消费者进程从共享内存中读取并输出序列。生产者进程要在命令行指定生成Catalan数的数目。例如,命令行指定5,说明生产者进程会生成5个Catalan数:1   2   5   14   42

这里的实现没有显式创建进程,因为打开不同的命令行窗口就于创建新进程。

//生产者(write)
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h>

#define MAX 32 
void *pAddr;
int shmId;
 
struct Msg{
  int flag;//0为读,1为写
  long long content[MAX];
};                          //content:存catalan数   flag:共享内存占用标志的信号
 
void Handle(int s){
  if(s == 2)
  {
     //本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
     shmdt(pAddr);     
     shmctl(shmId,IPC_RMID,0);  //完成对共享内存的控制,删除这片共享内存
     exit(0);
  }
} 
 


int main(){
  int n = 0;    //Catalan数的数目
  int i=0,j=0;
	
  
  /*
     按ctrl+c键退出时会处理这个消息,进行共享内存卸载、删除操作(handle功能),最后exit(0)退出程序
     signal函数和书上的信号量signal不一样,这里的功能使调用handle函数并把2作为handle的参数
  */
  signal(2,Handle);

  /*
    key_t ftok(char *fname,int id)将一个已存在的路径名和一个整数标识符转换成一个key_t值
    得到IPC通信的key,用于创建共享内存。"."表示文件名为当前目录,按照ftok的规则,由于我的read程 
    序也在当前目录,使用的ftok函数的参数相同,因此得到的key也相同
  */
  key_t key = ftok(".",2);
 
  /* 
     创建共享内存,shmId是共享内存标识符
     100表示申请的共享内存是100字节;IPC_CREAT | IPC_EXCL | 0666 :前两个保证创建新内存,否则返            
     回值为-1,0666是3位八进制数,6即二进制110,表示可读可写不可执行,从左到右分别对应当前用户, 
     group组用户,其他用户
  */  
  shmId = shmget(key,100,IPC_CREAT | IPC_EXCL | 0666); 

  pAddr = shmat(shmId,0,0);  //把共享内存区对象映射到调用进程的地址空间,随后可像本地地址空间一样进行访问,第二个参数指定为0让内核决定内存的位置,第三个参数0表示可读写
 
  if(*(int *)pAddr == -1){
    printf("shmat error!\n"); 
    exit(0);
  }
 
 
  memset(pAddr,0,100); //将pAddr处的100个字节设置为NULL
  struct Msg *msg = (struct Msg *)pAddr; //msg 指向共享内存
  msg->flag = 1;       //表示写进程占用共享内存
  while(1){
    if(msg->flag == 1){//当为1时写消息,此时读文件中不能操作此共享内存
      i=0;  
      for(i=0;i<MAX;i++)
	    msg->content[i]=0;    //初始化

      printf("The number of catalan:");
      scanf("%d",&n);
      msg->content[0] = 1;
      for(j=1;j<n;j++)
	    msg->content[j] = msg->content[j-1]*(4*j+2)/(j+2); //计算Catalan数

      msg->flag = 0;//当写消息后flag置为0,让读文件开始执行读操作,此时写文件不能进行写操作
    }
    else{
      sleep(1);        //停止1s,让读进程读取msg指向的数据(共享内存)并输出
    }
  }
  return 0;
}

 

//消费者(read)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <string.h>
#include <signal.h>
#define MAX 32
 
void *pAddr;
int shmId;
 
struct Msg{
  int flag;
  long long content[MAX];
};
 
int main(){
  int i=0;
  key_t key = ftok(".",2);
  shmId = shmget(key,0,0); //key与writed的key相同,后两个0表示获取该共享内存
  
  pAddr = shmat(shmId,0,0); //获取共享内存的地址
 
  if(*(int *)pAddr == -1){
    printf("shmat error!\n"); 
    exit(0);
  }
  
  struct Msg * msg = (struct Msg *)pAddr;
  while(1){
      if(msg->flag == 0){//当为0时读消息,此时写文件中不能操作此共享内存
      i=0;
      while(msg->content[i]!=0)
      {
           printf("%lld\n",msg->content[i]);
           i++;
      }

      msg->flag = 1;
    }
    else{
      sleep(1); 
    }
  } 
  
  return 0;
}

本文参考

参考源码  https://blog.csdn.net/qq_29762941/article/details/79985377

共享内存函数 https://blog.csdn.net/guoping16/article/details/6584058

signal()函数 https://blog.csdn.net/chenjianqi0502/article/details/78579541

shmget的参数https://blog.csdn.net/ec06cumt/article/details/51444961   https://blog.csdn.net/Fly_as_tadpole/article/details/81044096

ftok()函数

https://www.cnblogs.com/joeblackzqq/archive/2011/05/31/2065161.html  https://www.cnblogs.com/HectorInsanE/archive/2011/03/17/1986859.html

  • 3
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
semop是一个系统调用,它可以用于实现进程间的同步和互斥。在使用共享内存进行进程间通信时,需要使用信号量来实现同步和互斥。 下面是一个使用semop实现两个进程共享内存的示例: 首先,我们需要创建一个共享内存区域,以及两个信号量,一个用于互斥,一个用于同步: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define SHM_SIZE 1024 int main() { int shmid, semid; char *shmaddr; struct sembuf semop; key_t key; // 创建共享内存 key = ftok("/tmp/mem", 1); shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666); if (shmid == -1) { perror("shmget"); exit(1); } // 映射共享内存 shmaddr = shmat(shmid, NULL, 0); if (shmaddr == (char *)-1) { perror("shmat"); exit(1); } // 创建两个信号量,一个用于互斥,一个用于同步 semid = semget(key, 2, IPC_CREAT | 0666); if (semid == -1) { perror("semget"); exit(1); } // 初始化信号量 semctl(semid, 0, SETVAL, 1); // 互斥信号量初始值为1 semctl(semid, 1, SETVAL, 0); // 同步信号量初始值为0 // 进程1入数据 semop.sem_num = 0; semop.sem_op = -1; // 互斥信号量减1,获取锁 semop.sem_flg = SEM_UNDO; semop(semid, &semop, 1); memcpy(shmaddr, "hello world", 12); semop.sem_num = 1; semop.sem_op = 1; // 同步信号量加1,通知进程2 semop.sem_flg = SEM_UNDO; semop(semid, &semop, 1); // 进程2取数据 semop.sem_num = 1; semop.sem_op = -1; // 等待进程1入数据 semop.sem_flg = SEM_UNDO; semop(semid, &semop, 1); printf("%s\n", shmaddr); semop.sem_num = 0; semop.sem_op = 1; // 释放互斥锁 semop.sem_flg = SEM_UNDO; semop(semid, &semop, 1); // 删除共享内存和信号量 shmdt(shmaddr); shmctl(shmid, IPC_RMID, NULL); semctl(semid, 0, IPC_RMID, 0); return 0; } ``` 上述代码中,进程1先获取互斥信号量的锁,然后向共享内存入数据,并且通知进程2可以取数据了。进程2会在同步信号量上等待,直到进程1入数据后通知它,然后共享内存中的数据,并释放互斥信号量的锁。 需要注意的是,semop函数的第三个参数应该是操作信号量的个数,而不是信号量的编号。在本例中,我们只操作了一个信号量,所以第三个参数的值为1。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值