#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. 如何给sublime text.安装插件

    1.Sublime的Package Control安装方法 Package Control插件本身是一个为了方便管理插件的插件 第一步:ctrl+~,在弹出的下部边框中输入: 如果是 Sublime ...

  2. jQuery----jquery实现Tab键切换

    使用Jquery实现tab键切换,代码简洁易懂,实现逻辑清晰明了.具体总结如下: 需求分析: 鼠标进入tab切换模块,鼠标当前的模块上边框变为红色,并显示对应的商品名称.鼠标离开后,上边框恢复原色,图 ...

  3. 【转】如何内网搭建NuGet服务器

    原文:http://www.cnblogs.com/zhangweizhong/p/7755332.html NuGet 是.NET程序员熟知的工具,它可以直接安装开源社区中的各个公用组件,可以说是非 ...

  4. 大数据入门第十一天——hive详解(二)基本操作与分区分桶

    一.基本操作 1.DDL 官网的DDL语法教程:点击查看 建表语句 CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name [(col_name data ...

  5. Codeforces 1155 D Beautiful Array DP,最大子段和

    题意 给出一个长度为\(n\)的数列和数字\(x\),经过最多一次操作将数列的一个子段的每个元素变为\(a[i]*x\),使该数列的最大子段和最大 分析 将这个数列分为3段考虑,第一段和第三段是未修改 ...

  6. UWP 检测网络状态

    最近发现Community Toolkit有了网络辅助类,貌似很早就有了... 很不错,还是用.给大家分享一下. 1. 检测网络是否可用 2. 检测网络是否是计费模式? 3. 检测网络接入类型 4. ...

  7. python将oracle中的数据导入到mysql中。

    一.导入表结构.使用工具:navicate premium 和PowerDesinger 1. 先用navicate premium把oracle中的数据库导出为oracle脚本. 2. 在Power ...

  8. Selenium+Python自动化测试学习问题总结笔记

    1.问题描述:不能导入自定义类 错误内容:This inspection detects names that should resolve but don't. Due to dynamic dis ...

  9. Minor GC&Full GC&Major GC区别及触发条件

    Minor GC:从年轻代回收内存 触发条件 1.Eden区域满 ​ 2.新创建的对象大小 > Eden所剩空间 Full GC:清理整个堆空间,包括年轻代和老年代 触发条件 ​ 1.每次晋升到 ...

  10. OpenGL(1)-环境搭建

    写在前面 工作几年,开始沉心做技术,对自己的知识进行梳理. OpenGL是由khronos组织制定并维护的规范,并不是API. OpenGL在3.2之前采用的是立即渲染模式(固定渲染管线),3.2之后 ...