1、进程的同步互斥实验进程的同步互斥实验进程的同步互斥实验进程的同步互斥实验实验目的实验目的实验目的实验目的1 、进一步认识并发执行的实质2 、分析进程竞争资源的现象,学习解决进程同步互斥的方法实验内容实验内容实验内容实验内容1 、编写程序,使用相关函数实现父子进程对共享文件的同步互斥访问。2 、修改程序,观察对临界资源访问的互斥控制的作用。实验基础实验基础实验基础实验基础一、临界资源的互斥访问为了实现多进程对临界资源的互斥访问,一个进程访问临界资源的典型程序段类似如下形式: . 进入区临界区 ; 退出区其余代码 ; 其中,进入区中判 断资源是否可用,如果可用,则资 源数量减 1 ,进程进入临界区
2、 ;否则进程阻塞等待。 退出区中资源数量加 1 ,唤醒阻塞等待该 资源的进程。进入区和退出区都是原子操作。操作系统中 , 通常用信号量来实现进入区和退出区 , 即 P 操作和 V 操作 。 为了实现用户程序中对某些资源的同步互斥访问,操作系统也提供了一些函数接口,功能类似于对特定临界区的进入区和退出区功能。二、相关的系统调用( 1 ) l ockf ( f i l es , f unct i on, s i ze) : 用作锁定文件的某些段或者整个文件。函数原型:#incl ude i nt l ockf( i nt f i l e s , i nt f unct i on;l ongs i
3、z e )其 中: f i l e s 是 文件 描 述符 ; 参数 f unct i on 可 以取 以 下值 : F _LOCK : 锁定 一 个区 域 。F _UL OCK :解除锁 定。参数 s i z e 指明了从 文件当前位置开 始的一段连续锁定 区域的长度,当 s i z e 为 0 时,锁定记录将由当前位置一直扩展到文件尾。如果 l ockf 的参数 f unct i on 取值为 F _LOCK ,而指定文件的对应区域已被其他进程锁定 ,那么 l ockf 的调用进程将被阻塞直到该区域解锁。通过使用 l ockf 函数,可 实现多进程对共 享文件进行互斥访 问。进程的实现 中
4、,必须使得每个进程在使用文件前对文件加锁,使用文件后解锁。( 2 ) o pen:打开一个文件函数原型: #incl ude #incl ude#incl ude i nt open(c har *pat h,i nt f l a gs, m ode_t m ode) ;其中:参数 pat h 是指向所要打开的文件的路径名指针。参数 f a l gs 规定 如何打开 该文件 , 它必 须包含以 下值之一 : O_RDONLY ,只 读打开 ;O_WRONLY , 只写打开 ; O_RDWR , 读 / 写打开 ; O_CRE AT, 当文件不存在时创建文件 , 需参数 m ode ; O_AP
5、 P E ND, 不论当前文件位置 在何处 , 将文件指针移至文 件尾 , 为 w r i t e 添加数据到文件; O_TRUN C, 当以可写的方式成功打开普通文件时 , 截断该文件的长度为 0 。参数 m ode 规定对该文件的访问权限。open 系统调用 可以只使用前面介 绍的这两个参数 ,省略第三个参数 m ode 。第三个 参数是在用 O_CRE AT 创建文件时使用,指出新建文件的存取许可权。由这个参数指出的存取许可权还要和 um a s k 进行运算后才得到新建文件的真正存取许可权 。 该运算是由 um a s k 按位取反 , 再按位与上第三个参数给出的数取或 ( um a
6、s k系统调用根 据 whence 指定的位置将文件描述 符 fildes 指向文件的文件指针偏 移 offset长度的字节数。 Whence的取值及其含义如下: SEEK_SET:从文件头开始计算偏移量,文件指针值就是 offset的值。 SEEK_CUR:从文件指针的当前位置开始计算偏移量,文件指针值是当前指针的值加上 offset的值。 SEEK_END: 从文件末尾开始计算偏移量 , 文件指针的值是文件长度加上 offset的值 ,一般可能使用负的偏移量,使得文件指针从后向前移动。当 lseek调用成功时,返回值为一个字节为单位从文件头开始计算文件偏移量的值。调用失败时,返回值为 -
7、1 。文件指针又称文件读 / 写指针 。 文件刚打开时 , 文件指针指向开头位置 ; 文件读写都是从文件指针处开始, 并且在读写过程中同时移动文件指 针。 Lseek函数就是用于设置 文件指针位置。(6)close:关闭文件函数原型: #includeint close(intfd);每打开一个文件,系统就给文件分配一个文件描述符,同时为打开文件描述符的引用计数加 。 Linux文件系统最多可以分配 255个文件描述符 。 当调用 close()时 , 打开文件描述符的引用计数值减,最后一次对 close()的调用将使应用计数值为零。虽然当一个进程结束时,任何打开的文件将自动关闭,明显地关闭任
8、何打开的文件是良好的程序设计习惯。实验指导实验指导实验指导实验指导1 、 ( 1 ) 参照参考程序 1 , 编写程序 。 父进程和两个子进程分别连续向共享文件中写入 3 行字符串。多次运行程序 , 观察共享文件内容。( 2 )修改程序,去 掉所有 lock/unlock调用。多次运行 程序 , 观察分析共享文 件中, 3 个进程写入字符串的次序,解释原因。2 、 ( 1 ) 参照参考程序 2 , 编写程序 。 父进程从外界获取字符串 , 并将其写入共享文件 ; 子进程从共享文件中获取字符串,并将其打印出来。( 2 )修改程序,去掉所有 lock/unlock调用。观察分析运行结果,解释原因。(
9、 3 )修改程序,不是去掉 lock/unlock调用 , 而是去掉子进程中的 ” sleep(1);” 。观察分析运行结果,解释原因。参考程序参考程序参考程序参考程序参考程序 1# i n c l u d e # i n c l u d e i n t f a t a l ( c o n s t c h a r * i n f o )p e r r o r ( i n f o ) ;e x i t ( 1 ) ;i n t l o c k ( i n t f d )l s e e k ( f d , 0 , S E E K _ S E T ) ;i f ( l o c k f ( f d ,
10、 F _ L O C K , 0 ) = = - 1 )f a t a l ( “ l o c k f ( ) “ ) ;r e t u r n 0 ;i n t u n l o c k ( i n t f d )l s e e k ( f d , 0 , S E E K _ S E T ) ;i f ( l o c k f ( f d , F _ U L O C K , 0 ) = = - 1 )f a t a l ( “ u n l o c k f ( ) “ ) ;r e t u r n 0 ;i n t m a i n ( )i n t f d ;i n t p 1 , p 2 , i
11、 ;c h a r s t r 2 0 ;i f ( ( f d = o p e n ( “ l o c k e d _ f i l e . t x t “ , O _ R D W R | O _ A P P E N D | O _ C R E A T , 0 6 6 6 ) ) # i n c l u d e i n t f a t a l ( c o n s t c h a r * i n f o )p e r r o r ( i n f o ) ;e x i t ( 1 ) ;i n t l o c k ( i n t f d )l s e e k ( f d , 0 , S E E K
12、 _ S E T ) ;i f ( l o c k f ( f d , F _ L O C K , 0 ) = = - 1 )f a t a l ( “ l o c k f ( ) “ ) ;r e t u r n 0 ;i n t u n l o c k ( i n t f d )l s e e k ( f d , 0 , S E E K _ S E T ) ;i f ( l o c k f ( f d , F _ U L O C K , 0 ) = = - 1 )f a t a l ( “ u n l o c k f ( ) “ ) ;r e t u r n 0 ;i n t m a i
13、n ( )i n t p i d , f d ;c h a r s t r 8 0 ;f d = o p e n ( “ t m p . t x t “ , O _ R D W R | O _ C R E A T | O _ T R U N C , 0 6 4 4 ) ;p i d = f o r k ( ) ;s w i t c h ( p i d )c a s e - 1 :f a t a l ( “ f o r k f a i l ! “ ) ;c a s e 0 :s l e e p ( 1 ) ;l o c k ( f d ) ;l s e e k ( f d , S E E K _
14、 S E T , 0 ) ;r e a d ( f d , s t r , s i z e o f ( s t r ) ) ;u n l o c k ( f d ) ;p r i n t f ( “ s o n % d : r e a d s t r f r o m t m p f i l e : % s n “ , g e t p i d ( ) , s t r ) ;e x i t ( 0 ) ;d e f a u l t :l o c k ( f d ) ;p r i n t f ( “ p a r e n t % d : p l e a s e e n t e r a s t r f
15、o r t m p f i l e ( s t r l e n 8 0 ) : n “ , g e t p i d ( ) ) ;s c a n f ( “ % s “ , s t r ) ;l s e e k ( f d , 0 , S E E K _ S E T ) ;w r i t e ( f d , s t r , s t r l e n ( s t r ) ) ;u n l o c k ( f d ) ;w a i t ( 0 ) ;c l o s e ( f d ) ;e x i t ( 0 ) ;思考题思考题思考题思考题1 、函数 unlock 和 l ock 的实现中, l s e e k 的作用?2 、解释参考程序 1 , 2 中 l ock/unlock 的作用?3 、参考程序 2,子进程中的 ” sleep(1);” 的作用?