要求是:生产者进程生成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