操作系统#进程互斥验证性实验报告
正文
一、 实验目的
- 父进程和两个子进程分别连续向共享文件中写入3行字符串。多次运行程序,观察共享文件内容。
- 修改程序1,先去掉第一个子进程的lock/unlock调用,观察分析共享文件中,3个进程写入字符串的次序,解释原因。
- 去掉所有lock/unlock调用。多次运行程序,观察分析共享文件中,3个进程写入字符串的次序,解释原因。
二、 实验设备
- Windows 操作系统
- VMware workstation
三、 实验说明
- lockf(files,function,size) :用作锁定文件的某些段或者整个文件。
其中:files是文件描述符;参数function可以取以下值:F_LOCK:锁定一个区域。F_ULOCK:解除锁定。参数size指明了从文件当前位置开始的一段连续锁定区域的长度,当size为0时,锁定记录将由当前位置一直扩展到文件尾。
2.lseek(files, offset, whence): 控制文件的读写位置. 参数files 为已打开的文件描述词, 参数offset 为根据参数whence来移动读写位置的位移数.
欲将读写位置移到文件开头时: lseek(files, 0, SEEK_SET);
read:读文件
int read(int fd,void *buf,size_t nbytes)
3.从文件描述符fd所代表的文件中读取nbytes 个字节,到buf指定的缓冲区内。所读取的内容从当前的读/写指针所指示的位置开始,这个位置由相应的打开文件描述中的偏移值(off_set)给出,调用成功后文件读写指针增加实际读取的字节数。
返回: -1:错误;0:文件偏移值是在文件结束处;
整数:从该文件复制到规定的缓冲区中的字节数。通常这个字节数与所请求的字节数相同。
open:打开一个文件
int open(char *path,int flags,mode_t mode);
其中:参数path 是指向所要打开的文件的路径名指针。
参数falgs 规定如何打开该文件,它必须包含以下值之一 :
O_RDONLY,只读打开 ;
O_WRONLY,只写打开 ;
O_RDWR,读/写打开;
O_CREAT,当文件不存在时创建文件,需参数mode;O_APPEND,不论当前文件位置在何处,将文件指针移至文件尾,为write添加数据到文件;O_TRUNC,当以可写的方式成功打开普通文件时,截断该文件的长度为0。参数mode 规定对该文件的访问权限。
write:写文件
int write(int fd,void *buf,size_t nbytes)
该调用从buf所指的缓冲区中将nbytes 个字节写到描述符fd所指的文件中。
close:关闭文件
int close(int fd);
每打开一个文件,系统就给文件分配一个文件描述符,同时为打开文件描述符的引用计数加1。Linux文件系统最多可以分配255个文件描述符。当调用close()时,打开文件描述符的引用计数值减1,最后一次对close()的调用将使应用计数值为零。
虽然当一个进程结束时,任何打开的文件将自动关闭,明显地关闭任何打开的文件是良好的程序设计习惯。
四、 实验步骤
#include<fcntl.h>
#include<stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
int fatal (const char* info)
{
perror (info);
exit (1);
}
int lock(int fd)
{
lseek(fd,0,SEEK_SET);
if(lockf(fd,F_LOCK,0)==-1)
fatal("lockf()");
return 0;
}
int unlock(int fd)
{
lseek(fd,0,SEEK_SET);
if(lockf(fd,F_ULOCK,0)==-1)
fatal("unlockf()");
return 0;
}
int main()
{
int fd;
int p1,p2,i;
char str[20];
if((fd=open("result.txt",O_RDWR|O_APPEND|O_CREAT,0666))<0)
fatal("open");
write(fd,"=========\n",10);
while((p1=fork( ))== -1); /*创建子进程女儿进程*/
if (女儿进程==0)
{
lock(fd); /*加锁*/
for(i=0;i<3;i++)
{
sprintf(str,"daughter %d\n",i);
write(fd,str,strlen(str));
sleep(1);
}
unlock(fd); /*解锁*/
}
else
{
while((p2=fork( ))==-1); /*创建子进程儿子进程*/
if (儿子进程==0)
{
lock(fd); /*加锁*/
for(i=0;i<3;i++)
{
sprintf(str,"son %d\n",i);
write(fd,str,strlen(str));
sleep(1);
}
unlock(fd); /*解锁*/
}
else
{
lock(fd); /*加锁*/
for(i=0;i<3;i++)
{
sprintf(str,"parent %d\n",i);
write(fd,str,strlen(str));
sleep(1);
}
unlock(fd); /*解锁*/
wait(NULL);
wait(NULL);
}
}
close(fd);
}
五、 结果分析与总结
1.父亲女儿儿子进程中都有lock(fd),三者之间都相处排斥,因而等一个进程输出完毕后,解锁,下一个进程上锁进行输出,多次运行,效果一致,输出如图所示。
2.注释掉女儿进程进程中的lock(fd),则现在只有儿子进程中有lock(fd)与最后的else{}中含有lock(fd),从而两者互斥,儿子进程与两者不互斥,输出如图所示。
注释掉所以进程中的lock(fd),则他们之间没有任何的互斥关系,因而按照代码顺序,输出如图所示。
2021年4月23日