#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
#include <sys/shm.h>
#define PRO 1
#define CON 0
#define P -1
#define V +1
typedef int MySem;
MySem empty,full,mutex1,mutex2;
int *buf;
MySem newsem(int intVal)// 新建信号量
{
int r,semID;
semID=semget(0,1,IPC_CREAT|0666); //创建新信号量集
r=semctl(semID,0,SETVAL,intVal); //对指定信号量赋intVal值 返回值:如果成功,则为一个正数;如果失败,则为-1
return semID;//获得的信号量的标识,用于此后的信号量操作
}
void psem(MySem semID)//对ID为semID的信号量做p
{
struct sembuf s;
s.sem_num=0;
s.sem_op=P;
s.sem_flg=0;
int r=semop(semID,&s,1);//对指定的信号量执行P操作
}
void vsem(MySem semID)//对ID为semID的信号量做v
{
//unsigned short sem_num; 欲操作的信号量在信号量集中的编号
//short sem_op; 信号量PV操作的增量(例如+1或-1)
//short sem_flg; 额外选项标识(0表示无额外设置;IPC_NOWAIT表示不允许阻塞;
//SEM_UNDO表示进程结束时恢复信号量 等)};
struct sembuf s;
s.sem_num=0;
s.sem_op=V;
s.sem_flg=0;
int r=semop(semID,&s,1);//对指定的信号量执行V操作
}
void freesem(MySem semID)//注销ID为semID的信号量
{
int r;
r=semctl(semID,0,IPC_RMID);//IPC_RMID:注销(删除)信号量集,无需参数
} int init(int n)
{
int shpid;
shpid=shmget(0,sizeof(int)*(n+2),IPC_CREAT|0666);//create 共享存储区+2 in out
buf=(int *)shmat(shpid,0,0);//将共享存储区映射到用户进程空间
empty=newsem(n);//缓冲区单元格有n个,初始化标记为null,允许生产者进程一开始就连续执行k次
full=newsem(0); //初始时没有满标记单元格,置初值full=0
mutex1=newsem(1); //生产者的互斥
mutex2=newsem(1); //消费者的互斥
buf[n]=0; //缓冲区单元格in
buf[n+1]=0; //缓冲区单元格out
return shpid; //存储区id
}
void pro(pid_t pid,int n)
{
printf("<P> <%d> started\n",getpid());//取得进程识别码 旧版 新_getpid();
int index=buf[n]; //buf[n]->in 用来标识in的位置
psem(empty); //同步,如果没有足够p值的话会放入队列中,系统进行维护
psem(mutex1);
buf[n]=(buf[n]+1)%n;
buf[ buf[n]]=1;//模拟存入,置1
printf("P <%d> put an item to <%d>\n",getpid(),index);
vsem(mutex1);//回调p函数,取出队首,
vsem(full); }
/*
demo:
n=3
p:index = buf[3] =in=0 in=buf[3]=1 buf[1]=1
p:index = buf[3] =in=1 in=buf[3]=2 buf[2]=1
v:index = buf[4] =out=0 out=buf[4]=1 buf[1]=0
v:index = buf[4] =out=1 out=buf[4]=2 buf[2]=0
v:index = buf[4] =out=2
psem(full) 等待释放
p:index = buf[3] =in=2 in=buf[3]=0 buf[0]=1
回调v
v:out=buf[4]=0 buf[0]=0
....
*/
void con(pid_t pid,int n)
{
printf("<C> <%d> started\n",getpid());
int index=buf[n+1];//out
psem(full);
psem(mutex2);
buf[n+1]=(buf[n+1]+1)%n;
buf[buf[n+1]]=0;//模拟取出,置0
printf("C <%d> got an item from <%d>\n",getpid(),index);
vsem(mutex2);
vsem(empty);
}
int main()
{
int t,k,n;
printf("Please input n:\n");
scanf("%d",&n);
int shpid=init(n);
k=rand()%1+1;
pid_t pid; //定义进程标示符
while(1)
{
srand((unsigned)time(NULL));//每次置随机数种子
pid=fork();//建立一个新进程(子进程) ,返回子进程的进程ID 在子进程中返回0
//注意:子进程与原进程(父进程)共享代码段,并拥有父进程的其他资源(数据、堆栈等)的一个副本
if(pid==0) //子线程
{
t=rand()%2;//0,1
if(t==PRO)
pro(pid,n);
else if(t==CON)
con(pid,n);
return 0; //记得return
}
else //父进程
sleep(k);
}
int x1=shmdt(0);//断开已有的映射
int x2=shctl(shpid,IPC_RMID,0);
return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

复杂PC问题——信号量与共享存储区的更多相关文章

  1. Linux下复杂PC问题——多进程编程/信号量通信/共享存储区

    进程相关函数 pid_t fork(); 头文件:unistd.h,sys/types.h 作用:建立一个新进程(子进程),子进程与原进程(父进程)共享代码段,并拥有父进程的其他资源(数据.堆栈等)的 ...

  2. Linux 进程间通信(一)(经典IPC:消息队列、信号量、共享存储)

    有3种称作XSI IPC的IPC:消息队列.信号量.共享存储.这种类型的IPC有如下共同的特性. 每个内核中的IPC都用一个非负整数标志.标识符是IPC对象的内部名称,为了使多个合作进程能够在同一IP ...

  3. 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等

    一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...

  4. 【APUE】进程间通信之共享存储(mmap函数)

    共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式,因为进程可以直接读写内存,而不需要任何数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存则只 ...

  5. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  6. 【JDK源码分析】String的存储区与不可变性

    // ... literals are interned by the compiler // and thus refer to the same object String s1 = " ...

  7. C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区

    栈,就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区.里面的变量通常是局部变量.函数参数等.在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用.和堆一样 ...

  8. Java中的堆内存、栈内存、静态存储区

    一.栈 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用.但缺点是,存在栈中的数据大小与生存 ...

  9. 【JDK源码分析】String的存储区与不可变性(转)

    // ... literals are interned by the compiler // and thus refer to the same object String s1 = " ...

随机推荐

  1. jQuery的一点小结

    1.jQuery常用选择器 筛选: $('div').has('p'); // 选择包含p元素的div元素 $('div').not('.myClass'); //选择class不等于myClass的 ...

  2. 腾讯云Mac图床插件

    背景 随着博客越写越多,难免会遇到需要插入图片来说明的情况. 图床选择 首先调研了市面上的图床服务,本着稳定长期的目标,过滤掉了打一枪换一个地方的野鸡小网站,剩余比较靠谱的优缺点如下. 图床 优点 缺 ...

  3. 使用C语言给php写扩展

    1.在php源码路径的ext文件夹下,新建一个extend_test.def文件,编辑文件内容为 string my_test_function(string str,int n) 2.在当前目录执行 ...

  4. Verdi调用VCS进行交互式仿真

    前一篇介绍了使用Verdi的后处理模式查看仿真波形进行调试,此外Verdi还支持交互模式,可以调用外部仿真器,下面介绍Verdi调用VCS进行交互模式仿真的方法.注意,这里介绍的方法需要2016版的V ...

  5. 托管代码编写mssql存储过程

    参考:http://wenku.it168.com/d_000642903.shtml 打开vs,创建数据库项目,添加新项,选择sql clr c#, 选择存储过程. 样例: [Microsoft.S ...

  6. SSM-CRUD入门项目——环境搭建

    一.项目概述 项目功能点: 1.分页 2.数据校验: jQuery前端校验+JSR303后端校验 3.ajax 4.RESTful风格的URI 技术点: 1.基础框架——SSM 2.数据库——MySQ ...

  7. 复制文件到IDE等工具出现乱码解决方案

    首要的解决方案是设置文件或者项目或者工作空间的编码,可以采用在文件上.项目上右键->properties进行设置 第二种方式是在editplus等编辑器里打开文件,然后打开文件之后点击菜单Fil ...

  8. struts2第三天——值栈

    大致内容: ognl概述 ognl入门 值栈 一.OGNL概述 OGNL,全称为Object-Graph Navigation Language,对象图导航语言 它是一个功能强大的表达式语言,用来获取 ...

  9. 20155237 2016-2017-2 《Java程序设计》第2周学习总结

    教材学习内容总结 通过教材了解了JAVA可区分为基本类型和类类型(参考类型)两大类型系统. 基本类型 分类 整数 short(2) / int(4) / long(8) 字节 byte(-128-12 ...

  10. 2018"百度之星"程序设计大赛 - 资格赛 1002 子串查询

    题面又是万能的毒毒熊... 实在不想写了,就只写了这题 记26个前缀和查询枚举最小值直接算 实在是氵的死 而且我忘记输出Case #%d 想了很久 >_< #include<bits ...