操作系统课程设计报告
题目:进程控制与进程通信
学 生 姓 名:
学
专
班
号:
业:
级:
指 导 教 师:
完 成 日 期: 2019 年 3 月 7 日
目录
一、 实验题目选择…………………………………………………………………………2
二、 实验目的………………………………………………………………………………2
三、实验环境搭建……………………………………………………………………………2
四、 实验思想………………………………………………………………………………3
五、 实验内容………………………………………………………………………………6
六、 实验总结………………………………………………………………………………11
1
进程控制与进程通信
一、实验题目选择
二、实验目的
求 10000 个浮点数和、平均值。父进程随机产生 10000 个浮点数,创
建四个子进程分别求 2500 个数的和、平均值,统计计算时间。
三、实验环境搭建
(1)硬件环境:装有 Linux 操作系统(虚拟机)的计算机一台。
Linux 系统桌面:
2
(2)软件环境:gcc 编辑器,可运行 C 语言程序。
四、 实验思想
1、gcc 编辑器:
在为 Linux 开发应用程序时, 绝大多数情况下使用的都是 C 语言,因此几乎每一 位
Linux 程序员面临的首要问题都是如何灵活运用 C 编译器。目前 Linux 下最常 用的 C
语言编译器是 GCC (GNU Compiler Collection ),它是 GNU 项目中符合 ANSI C 标准
的编译系统, 能够编译用 C、C++和 Object C 等语言编写的程序。 GCC 不仅功能非常
强大, 结构也异常灵活。 最值得称道的一点就是它可以通过不同的 前端模块来支持
各种语言,如 Java、 Fortran 、Pascal 、Modula-3 和 Ada 等。
开放、自由和灵活是 Linux 的魅力所在,而这一点在 GCC 上的体现就是程序员通 过它
能够更好地控制整个编译过程。 在使用 GCC 编译程序时,编译过程可以被细 分为四个
阶段:
◆ 预处理( Pre-Processing )
◆ 编译( Compiling )
◆ 汇编( Assembling )
◆ 链接( Linking )
Linux 程序员可以根据自己的需要让 GCC 在编译的任何阶段结束,以便检查或使 用编
译器在该阶段的输出信息,或者对最后生成的二进制文件进行控 制,以便 通过加入不
同数量和种类的调试代码来为今后的调试做好准备。 和其它常用的编 译器一样, GCC
也提供了灵活而强大的代码优化功能,利用它可以生成执 行效 率更高的代码。
GCC 提供了 30 多条警告信息和三个警告级别,使用它们有助于增强程序的稳定 性和可
移植性。此外, GCC 还对标准的 C 和 C++语言进行了大量的扩展,提高程 序的执行效
率,有助于编译器进行代码优化,能够减轻编程的工作量。
2、进程控制理论
① 进程是一个具有一定独立功能的程序的一次运行活动(动态性、并发性、独立性、
异步性)。
进程的四要素:
(1)有一段程序供其执行(不一定是一个进程所专有的),就像一场戏必须有自
己的剧本。
(2)有自己的专用系统堆栈空间(私有财产)
(3)有进程控制块(task_struct)(“有身份证,PID”)
(4)有独立的存储空间。
缺少第四条的称为线程,如果完全没有用户空间称为内核线程,共享用户空间的称
为用户线程。
② 经典进程三态:阻塞、就绪、执行
3
备注:在同一时刻 CUP 运行的只有一个进程
③ 进程 ID(PID):标识进程的唯一数字;父进程 ID(PPID);启动进程的用户 ID(UID)
④ 进程互斥:当有若干进程都要使用某一共享资源时,任何时候最多允许一个进程使
用,其它要使用该资源的进程必须等待,知道占用该资源的进程释放了该资源为止
⑤ 临界资源:操作系统中将一次只允许一个进程访问的资源称为临界资源
⑥ 临界区:进程中访问临界资源的那段代码称为临界区。为实现对临界资源的互斥访
问,应保证诸进程互斥的进入各自的临界区
⑦ 进程同步:一组并发进程按一定顺序执行的过程称为进程间的同步
⑧ 进程调度:按一定算法,从一组待运行的进程中选出一个来占有 CPU 运行
(1)调度方式:抢占式(A 正在运行,B 就绪,B 优先级高,直接运行 B)和非抢占式
(A 正在运行,B 就绪,B 优先级高,等 A 运行完再运行 B)
(2)调度算法:先来先服务, 短进程优先, 高优先级优先,时间片轮转
⑨ 死锁:多个进程因竞争临界资源而形成的一种僵局
⑩ 获取 ID
pid_t getpid(void);
//获取本进程 ID
pid_t getppid(void);
⑪ 进程创建:
pid_t fork(void);
//获取父进程 ID
//创建子进程
4
fork 被调用一次,却返回两次,他可能有三种不同的返回值
(1)在父进程中,fork 返回新创建的子进程的 PID
(2)在子进程中,fork 返回 0
(3)如果出现错误,fork 返回一个负值
注:fork 后的代码由两个进程运行,即两个进程共享一段代码,但会拷贝一份数据,
即子进程的数据空间、堆栈空间都会从父进程得到一份拷贝,而不是共享。
pid_t vfork(void)
⑫ 进程创建的另一个函数:
⑬ exec 函数族:用被执行的程序替换调用它的程序
⑭system 函数:运行一条命令
(1)system 原型:int system(const char* command);
3、进程通信方法
①管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有
亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
② 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘
关系进程间的通信。
③信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源
的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资
源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
④ 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息
队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓
冲区大小受限等缺点。
⑤ 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件
已经发生。
⑥共享内存( shared memory):共享内存就是映射一段能被其他进程所访问的内存,这
段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它
是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号
量,配合使用,来实现进程间的同步和通信。
⑦ 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,
它可用于不同及其间的进程通信。
管道的主要局限性正体现在它的特点上:
只支持单向数据流;
只能用于具有亲缘关系的进程之间;
没有名字;
管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面
大小);
管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的
格式,比如多少字节算作一个消息(或命令、或记录)等等;
5
4、fork 函数:
函数原型:pid_t fork( void);
返回值: 若成功调用一次则返回两个值,子进程返回 0,父进程返回子进
程 ID;否则,出错返回-1
一个现有进程可以调用 fork 函数创建一个新进程。由 fork 创建的新进程被称为子
进程(child process)。fork 函数被调用一次但返回两次。两次返回的唯一区别是子
进程中返回 0 值
而父进程中返回子进程 ID。
linux 内核下 fork 使用 COW 机制工作原理:
进程 0(父进程)创建进程 1(子进程)后,进程 0 和进程 1 同时使用着共享
代码区内相同的代码和数据内存页面, 只是执行代码不在一处,因此他们也同时使用着
相同的用户堆栈区。在为进程 1(子进程)复制其父进程(进程 0)的页目录和页表项时,
进程 0 的 640KB 页表项的属性没有改动过(仍然可读写),但是进程 1 的 640KB 对应的页
表项却被设置成只读。因此当进程 1(子进程)开始执行时,对用户堆栈的入栈操作将
导致页面写保护异常,从而使得内核的内存管理程序为进程 1 在主内存区中分配一内存
页面,并把进程 0 中的页面内容复制到新的页面上。从此时开始,进程 1 开始有自己独
立的内存页面。
由于此时的内存页面在主内存区,因此进程 1 中继续创建新的子进程时也可以
采用 COW 技术。 内核调度进程运行时次序是随机的,进程 0 创建进程 1 后,可能先于
进程 1 修改共享区,进程 0 是可读写的,在未分开前,进程 1 是只读的,由于两个进程
共享内存空间。
fork()后立即执行 exec(),地址空间就无需被复制了,一个进程一旦调用 exec
类函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,废弃原有的 数
据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就
是说,对系统而言,还是同一个进程,不过已经是另一个程序了。
fork()的实际开销就是复制父进程的页表以及给子进程创建一个进程描述符。
在一般情况下,进程创建后都为马上运行一个可执行的文件,采用 COW 这种优化,
可以避免拷贝大量根本就不会被使用的数据(地址空间里常常包含数十兆的数
据)。由于 Unix 强调进程快速执行的能力,所以这个优化是很重要的。
五、 实验内容
1、求 10000 个浮点数和、平均值流程图:
6
2、具体步骤:
1、随机生成 10000 个浮点数
2、创建 4 个子进程,分别求 2500 个数的和
3、父进程完成 10000 个浮点数之和和平均值并输出
4、通过 clock 函数获取进程开始和结束的时间,再相减得出进程计算
时间。
3、程序代码(源代码):
#include
#include
#include
#include
7