#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. OO第一次博客作业总结反思

    使用了masteruml插件来生成类图和metrics插件分析代码 第一次作业 1.UML类图 >在第一次作业中,使用了两个类,代码中有没有使用的变量与函数,为平衡两个类的内容,我将输出函数放在 ...

  2. #leetcode刷题之路39-组合总和

    给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合.candidates 中的数字可以无限制重复被选取 ...

  3. Delphi - SPcomm 控件使用

    Com口函数 自动获取Com口,函数列表 procedure EnumComPorts(Ports: TStrings); //自动获取com口函数 var KeyHandle: HKEY; ErrC ...

  4. VIM - visual selection 模式下的简单操作

    1. 概述 vim 的 visual selection 模式下的简单操作 2. visual selection 模式 概述 可视化选择 可视化选择 vim 的一种专门用来选择的模式 可以提供相对于 ...

  5. 【转】mxGraph教程-开发入门指南

    原文:https://blog.csdn.net/sunhuaqiang1/article/details/51289580 mxGraph教程-开发入门指南 概述 mxGraph是一个JS绘图组件适 ...

  6. 20145209刘一阳《JAVA程序设计》第七周课堂测试

    第七周课堂测试 1.命令"CREATE DATABASE "用来创建一个数据库.(A) A .true B .false 2.以下不属于驱动的四种类型的是(C) A .JDBC-O ...

  7. [NOI2007]货币兑换 cdq分治,斜率优化

    [NOI2007]货币兑换 LG传送门 妥妥的\(n \log n\)cdq做法. 这题用cdq分治也可以\(n \log n\)但是在洛谷上竟然比一些优秀的splay跑得慢真是见了鬼了看来还是人丑常 ...

  8. RegExp正则匹配模式汇总

    正则表达式提供另一种强大的文本搜索和处理方式,对于正则表达式,不同语言有着不同的实现,JavaScript采用的Perl5的语法.对于极少数匹配模式是简单的全字符文本的情况,我们往往会采用indexO ...

  9. 精确的double加减乘除运算工具类

    import java.math.BigDecimal; /** * 精确的double加减乘除运算 * @author cyf * */ public class DoubleUtil { /** ...

  10. Centos6.8操作防火墙

    设置防火墙iptables开放3306接口 在/etc/sysconfig下面有个iptables文件,在控制台输入命令 iptables -I INPUT -p tcp --dport 3306 - ...