实验三 使用Linux高级IPC 陈毅东.

Slides:



Advertisements
Similar presentations
实验二 Linux 线程及信号灯 一、目的 了解并掌握 Linux 线程及信号灯。 二、要求 1 、了解 Linux 线程与信号灯使用: ( 1 ) Linux 线程 ( 2 ) Linux 信号灯 ( 3 )线程互斥 ( 4 )线程同步.
Advertisements

阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Linux 系统. 操作系统发展需求 1 没有操作系统 2 简单批处理操作系统 3 多道程序设计的批处理 4 多道程序设计的分时操作系统 5 多处理机并行系统 6 网络操作系统 7 分布式操作系统.
第十章 UNIX系统内核结构 10.1 UNIX系统概述 10.2 进程的描述和控制 10.3 进程的同步与通信 10.4 存储器管理
第一章 C语言概述 计算机公共教学部.
Oracle数据库 Oracle 子程序.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
Operating System Process Management - 4 Monday, August 11, 2008.
Using C++ The Weird Way Something about c++11 & OOP tricks
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
chapter 1-Introduction
第7章 Linux环境编程.
多进程编程.
进程及进程管理 第4章 进程及进程管理.
实验、进(线)程同步与通信 一、实验目的 1、掌握Linux系统用户界面中键盘命令的使用。 2、学会一种Linux下的编程环境。
管理信息结构SMI.
实践演练 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
走进编程 程序的顺序结构(二).
辅导课程六.
中国科学技术大学计算机系 陈香兰(0512- ) Autumn 2010
进程操作.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
文件读写实践 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
第五讲 四则运算计算器(一) 精品教程《C#程序设计与应用(第2版)清华大学出版社 谭恒松 主编
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
如何生成设备节点 广州创龙电子科技有限公司
Linux 文件操作——系统调用和标准 IO 库
Windows 7 的系统设置.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第七章 操作符重载 胡昊 南京大学计算机系软件所.
实验一、进程控制 一、实验目的 1、加深对进程的理解,进一步认识并发执行的实质; 2、分析进程争用资源现象,学习解决进程互斥的方法;
第2章 进程管理 2.1 进程概念 2.2 线程 2.3 进程管理 2.4 进程间通信 2.5 经典进程同步问题 2.6 管程
第2章 进程和线程 内容提要: 2.1 进 程 概 念 2.2 进程的状态和组成 2.3 进 程 管 理 2.4 线 程.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
实验二、线程同步与通信 一、实验目的 1、掌握Linux下线程的概念; 2、了解Linux线程同步与通信的主要机制;
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
实验三、共享内存与进程同步 一、实验目的 1、掌握Linux下共享内存的概念与使用方法; 2、掌握环形缓冲的结构与使用方法;
实验三、共享内存与进程同步 一、实验目的与要求 二、实验内容
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
姚金宇 MIT SCHEME 使用说明 姚金宇
3.5 线程 问题的提出 进程的引入使操作系统得以完成对并发执行的多道程序动态特征的描述和资源共享的管理,因而进程既是调度的基本单位又是资源分配的基本单位。进程所具有的这两个特点构成了程序并发执行的基础,但同时又导致进程切换过程中由于进程映像过大而带来的时空开销。因此,如果系统中创建的进程过多,或进程切换的频率过高,则会使系统效率下降,限制了并发度的进一步提高。
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Select模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
信号量(Semaphore).
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
iSIGHT 基本培训 使用 Excel的栅栏问题
3.16 枚举算法及其程序实现 ——数组的作用.
第二章 类型、对象、运算符和表达式.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
第 7 章 进程间的通信.
#include <iostream.h>
_08文件操作 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
Google的云计算 分布式锁服务Chubby.
2017 Operating Systems 作業系統實習 助教:陳主恩、林欣穎 實驗室:720A Lab4.
基于列存储的RDF数据管理 朱敏
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
FVX1100介绍 法视特(上海)图像科技有限公司 施 俊.
实验三 Linux文件目录操作 一、目的 二、要求 了解并掌握Linux文件目录结构。 了解Linux文件系统与目录操作:
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
本节内容 SEMAPHORE 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
《操作系统设计与实现》 Linux系统编程.
Presentation transcript:

实验三 使用Linux高级IPC 陈毅东

提纲 进程间通信概述 目标问题——哲学家进餐问题 Linux高级IPC机制 实现的其他问题 实习题 问题描述 错误与不好的解法 结束 提纲 进程间通信概述 目标问题——哲学家进餐问题 问题描述 错误与不好的解法 并行度较高的解法 Linux高级IPC机制 概述 System V信号灯 System V共享内存区 实现的其他问题 实习题

进程间通信概述(1):引子 输出结果是什么? #include <unistd.h> #include <sys/types.h> int result; main() { pid_t pid; result=0; pid=fork(); if(pid<0) exit(-1); else{ sleep(3); result=result+10; exit(0); } while(wait((int*)0)!=-1); printf("%d\n", result); exit(0); } if(pid){ pid=fork(); if(pid<0) exit(-1); if(pid==0){ sleep(3); result=result+20; exit(0); } } 输出结果是什么?

进程间通信概述(2) 进程是相互独立的,进程间的通信需要专门的机制。 进程之间的通信可以经由文件系统,但实际使用较为复杂(例如,需要锁机制)。 UNIX IPC (InterProcess Communication)机制是各种进程通信方式的统称。 Linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。

进程间通信概述(3) 对于UNIX的发展,贝尔实验室和BSD在进程间通信方面的侧重点有所不同: 贝尔实验室对Unix早期的进程间通信手段进行了系统的改进和扩充,形成了“System V IPC”,通信进程局限在单个计算机内; BSD则主要考虑跨计算机的进程间通信,形成了基于套接口(socket)的进程间通信机制。

进程间通信概述(4) 最初的Unix IPC:信号、管道、FIFO; System V IPC:消息队列、信号量、共享内存区; 返回 进程间通信概述(4) 最初的 UNIX IPC System V IPC 基于Socket的IPC Linux IPC POSIX IPC 最初的Unix IPC:信号、管道、FIFO; System V IPC:消息队列、信号量、共享内存区; POSIX IPC:消息队列、信号量、共享内存区。

哲学家进餐问题的描述 五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一碗米饭,相邻的两碗之间有一支筷子(如图)。 返回 哲学家进餐问题的描述 五个哲学家围坐在一张圆桌周围,每个哲学家面前都有一碗米饭,相邻的两碗之间有一支筷子(如图)。 哲学家的生活包含两种活动:即吃饭和思考。当一个哲学家觉得饿时,他就试图分两次去取他左边和右边的筷子,每次拿起一支,但不分次序。如果成功地获得了一双筷子,他就开始吃饭,吃完以后放下筷子继续思考。这样,问题就是,为每个哲学家写一段程序来描述其行为,要求不死锁。

错误与不好的解法(1) 解法一:可能进入“死锁”状态 若每个哲学家进程都运行到此句后发生进程切换,则进入死锁。 #define N 5 void philosopher(int i) { while(TRUE){ think(); take-chopstick(i); take-chopstick((i+1)%N); eat(); put-chopstick(i); put-chopstick((i+1)%N); } 若每个哲学家进程都运行到此句后发生进程切换,则进入死锁。

错误与不好的解法(2) 解法二:可能进入“饥饿”状态   这种解法可能会造成下面情况:哲学家们不断地重复“拿起各自左边的筷子又放下”的动作,谁也不能进餐。注意:这时和解法一的状态不同,这时进程都没有阻塞。 #define N 5 void philosopher(int i) { while(TRUE){ think(); do{ take-chopstick(i); if(can-take-chopstick((i+1)%N)) break; else put-chopstick(i); }while(TRUE); eat(); put-chopstick(i);put-chopstick((i+1)%N); } 不妨假设此函数能做到“测试且设置”。

错误与不好的解法(3) 解法三:可行但效率低下 返回 错误与不好的解法(3) 解法三:可行但效率低下   本解法从理论上可行,但从实际角来看,有一局限性:同一时刻只能有一位哲学家进餐。而这里有五支筷子,实际上应能允许两位哲学家同时进餐。 #define N 5 typedef int semaphore; semaphore mutex=1; void philosopher(int i) { while(TRUE){ think(); down(mutex); take-chopstick(i); take-chopstick((i+1)%N); eat(); put-chopstick(i); put-chopstick((i+1)%N); up(mutex); }

并行度较高的解法(1) void philosopher(int i) { while(TRUE){ think(); take-chopsticks(i); eat(); put-chopsticks(i); } } #define N 5 #define LEFT (i+N-1)%N #define RIGHT (i+1)%N #define THINKING 0 #define HUNGRY 1 #define EATING 2 typedef int semaphore; int state[N]; semaphore mutex=1; semaphore s[N];

并行度较高的解法(2) void put-chopsticks(int i) void take-chopsticks(int i) { { 返回 并行度较高的解法(2) void take-chopsticks(int i) { down(&mutex); state[i]=HUNGRY; test(i); up(&mutex); down(&s[i]); } void put-chopsticks(int i) { down(&mutex); state[i]=THINKING; test(LEFT); test(RIGHT); up(&mutex); } void test(i) { if(state[i]==HUNGRY &&state[LEFT]!=EATING&&state[RIGHT]!=EATING){ state[i]=EATING;up(&s[i]); }

概述 System V IPC包含了三种机制,在实现“哲学家进餐问题”时,我们只使用信号灯机制和共享存储区机制。主要的函数如下: 返回 概述 System V IPC包含了三种机制,在实现“哲学家进餐问题”时,我们只使用信号灯机制和共享存储区机制。主要的函数如下: 信号灯 共享内存区  头文件 <sys/sem.h> <sys/shm.h>  创建或打开IPC semget shmget  控制IPC操作 semctl shmctl  IPC操作函数 semop shmat, shmdt System V IPC对象以key_t类型的值作为其名字。 System V IPC对象以一定的存取权限来控制其访问。

返回 System V IPC的名字 System V IPC是有名的,这样可以支持无亲缘关系的进程访问同一的IPC对象。其名字的类型为key_t,可以由ftok函数赋予或直接取值IPC_PRIVATE。 ftok函数 原型:#include <sys/types.h>    #include <sys/ipc.h>    key_t ftok(const char * pathname, int id); 功能:把已存在的路径名和一整数标识符转换成一个key_t值,称为IPC键。 返回值:成功时返回IPC键,出错返回-1。 说明:1、ftok产生的键值不会是IPC_PRIVATE;    2、不能保证ftok生成的键值唯一;    3、用于产生键的文件不能在该IPC对象存活其  内删除。

System V IPC对象的存取权限 为防止共享的IPC对象被非法访问,必须为IPC对象设置存取权限。 返回 System V IPC对象的存取权限 为防止共享的IPC对象被非法访问,必须为IPC对象设置存取权限。 System V IPC对象的存取权限和文件系统中文件的存取权限类似,也用9位分3组表示,三组分别代表属主、组成员和其他用户对该IPC对象的存取权限;每组中三位,只用其中的两位表示是否可读和是否可写。一般为了安全,在创建IPC对象时应该设置存取权限制为0600,表示仅仅对属主是可读,可写的。

返回 System V信号灯 semget semctl semop down和up的实现

semget(1)——函数说明 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/sem.h>    int semget(key_t key, int nsems, int oflag); 功能:创建或打开信号灯集合。 返回值:成功返回非负信号灯标识符,出错返回-1。 说明:1、key是欲创建或打开的信号灯集合的名字;    2、nsems指明信号灯集合中包含的信号灯数;    3、oflag是一个位信息标志,含两部分信息,即存    取权限和控制字段。低9位表示存取权限,控    制字段中IPC_CREAT位和IPC_EXCL位的设    置情况与参数key共同决定了本调用的操作。

返回 semget(2)——工作流程 if (key==IPC_PRIVATE) 创建新信号灯集并返回其id; else if (与key相关的信号灯集合存在) if ((oflag&IPC_CREAT)&&(oflag&IPC_EXCL)) 返回-1; else if (访问权限允许) 返回与key相关的信号灯集id; else 返回-1; else if (oflag&IPC_CREAT) 创建新信号灯集并返回其id; else 返回-1;

semctl(1)——函数说明 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/sem.h>    int semctl(int semid, int semnum, int cmd,     union semun arg); 功能:对semid标识的信号灯集合进行控制。 返回值:成功返回非负值,出错返回-1。 说明:1、cmd是对信号灯集的控制命令,有GETVAL,      SETVAL,GETALL,SETALL,IPC_RMID      等,我们只用最后的两个。    2、semnum标识该信号灯集中某成员(以0为第      一个),仅用于GETVAL,SETVAL等命令。    3、arg是可选的,取决于参数cmd,GETALL或      SETALL等命令就要用到参数arg。

semctl(2)——union semun 返回 semctl(2)——union semun union semun的定义为: union semun{ int val; //仅用于SETVAL命令 struct semid_ds * buf; //用于IPC_SET等命令 ushort * array; //用于SETALL等命令 } 注意,本联合未在出现在任何系统头文件中,因此必须由应用程序声明。

semop(1)——函数说明 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/sem.h>    int semop(int semid,     struct sembuf * opsptr,     size_t nops); 功能:对semid标识的信号灯集合中信号灯进行操作。 返回值:成功返回0,出错返回-1。 说明:1、opsptr是指向结构struct sembuf的指针,可      以是这种类型的结构数组的头指针。数组的每      个元素包含对信号灯集合中一个信号的的操作      的信息,从而可实现同时对多信号灯的操作。    2、nops指出opsptr指向的结构数组中元素数。

semop(2)——struct sembuf 返回 semop(2)——struct sembuf struct sembuf的定义为: struct sembuf{ short sem_num; //信号灯号:0,1,…,nsems-1 short sem_op; //信号灯操作:<0, 0, >0 short sem_flg; //操作标识:这里我们只要置0 } sem_op不同值对应的操作(设信号灯当前值为sv): sem-op<0: start: if (sv>=abs (sem_op)) sv=sv-abs(sem_op); else {sleep; goto start;} sem_op>0: sv=sv+sem_op; 唤醒所有阻塞于该信号量的进程; sem_op==0:测试sv是否为0。

down和up的实现 void down(int sid, int sn) void up(int sid, int sn) { { 返回 down和up的实现 void down(int sid, int sn) { struct sembuf op; op.sem_num=sn; op.sem_op=-1; op.sem_flg=0; semop(sid, &op, 1); } void up(int sid, int sn) { struct sembuf op; op.sem_num=sn; op.sem_op=1; op.sem_flg=0; semop(sid, &op, 1); }

返回 System V共享内存区 shmget shmctl shmat和shmdt 使用共享内存区的一般流程

返回 shmget 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/shm.h>    int shmget(key_t key, size_t size, int oflag); 功能:创建或打开共享内存区。 返回值:成功返回非负内存区标识符,出错返回-1。 说明:1、size指明共享内存区大小(字节为单位);    2、key和oflag的说明基本和semget相同;    3、打开或创建一个共享内存区,并没提供调用进      程访问该内存区的手段。必须调用shmat。

返回 shmctl 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/shm.h>    int shmctl(int shmid, int cmd,     struct shmid_ds *buff); 功能:对shmid标识的共享内存区进行控制。 返回值:成功返回0,出错返回-1。 说明:1、参数cmd是对共享内存区的控制命令,可以是      IPC_RMID,IPC_SET或IPC_STAT,我们仅      用第一个;    2、buff主要用于命令IPC_SET和IPC_STAT,命      令为IPC_RMID时可直接提供NULL;

返回 shmat和shmdt 原型:#include <sys/types.h>    #include <sys/ipc.h>    #include <sys/shm.h>    void * shmat(int shmid,     const void * shmaddr,     int flag);    int shmdt(const void * shmaddr); 功能:shmat用于将一个打开的共享内存区附接到调用进程的地址空间。shmdt用于切断这个内存区域。 返回值:出错返回-1,shmat成功返回映射区的起始地址而shmdt成功时候返回0。 说明:shmat中shmaddr和flag可用来影响映射区起始地址的选取。一般应该分别提供NULL和0。

使用共享内存区的一般流程 使用System V共享内存区时的一般流程: 用shmget创建或打开一个共享内存区 返回 使用共享内存区的一般流程 使用System V共享内存区时的一般流程: 用shmget创建或打开一个共享内存区 用shmat将打开的共享内存区附接到进程地址空间 对共享内存区进行操作 用shmdt切断共享内存区与本进程地址空间的联系 用shmctl拆除共享内存区(用命令IPC_RMID)

返回 实现的其他问题 如何创建多个进程 创建一个进程链 创建一个进程扇 创建一个进程树 程序的结束 程序失败后如何释放资源

创建一个进程链 1 2 3 注意:本程序未考虑fork失败的情况。 4 #define N 4 返回 创建一个进程链 1 2 3 4 #define N 4 #include <stdio.h> #include <sys/types.h> #include <unistd.h> main() { int i; for (i=1;i<N;++i) if (fork()) break; fprintf(stderr, "#%d is process %ld with parent %ld\n", i, (long)getpid(), (long)getppid()); } 注意:本程序未考虑fork失败的情况。

创建一个进程扇 1 2 3 4 注意:本程序未考虑fork失败的情况。 #define N 4 返回 创建一个进程扇 1 2 3 4 #define N 4 #include <stdio.h> #include <sys/types.h> #include <unistd.h> main() { int i; for (i=1;i<N;++i) if (fork()==0) break; fprintf(stderr, "#%d is process %ld with parent %ld\n", i, (long)getpid(), (long)getppid()); } 注意:本程序未考虑fork失败的情况。

创建一个进程树 2a 1 3a 3b 3c 3d 2b 注意:本程序未考虑fork失败的情况。 #define N 4 返回 创建一个进程树 2a 1 3a 3b 3c 3d 2b #define N 4 #include <stdio.h> #include <sys/types.h> #include <unistd.h> main() { int i, id=0; for (i=1;i<N;++i) if (fork()==0) id=i; fprintf(stderr, "#%d is process %ld with parent %ld\n", id, (long)getpid(), (long)getppid()); } 注意:本程序未考虑fork失败的情况。

程序的结束 在什么时机结束程序 程序结束时候要记得回收IPC资源 返回 程序的结束 在什么时机结束程序 以某个外部文件的存在与否来决定:每个哲学家在“吃”完后都检测某个特定的文件(例如:~/quit)是否已经被创建。若是则结束程序。 利用信号(signal)截取键盘Ctrl-C信号。 程序结束时候要记得回收IPC资源

程序失败后如何释放资源 杀掉垃圾进程 删除垃圾IPC资源 使用ps –ax查看所有进程 使用killall name进行删除 返回 程序失败后如何释放资源 杀掉垃圾进程 使用ps –ax查看所有进程 使用killall name进行删除 删除垃圾IPC资源 使用ipcs [-a]查看所有IPC资源 使用ipcrm [shm|sem] id进行删除

实习题 理解实现进程通信的难点 练习创建多个进程的方法 解决哲学家进餐问题 实现不好的或有错误的算法,观察运行情况 返回 实习题 理解实现进程通信的难点 练习创建多个进程的方法 解决哲学家进餐问题 实现不好的或有错误的算法,观察运行情况 实现正确的算法(需要检查) 也实现其他方法