班级:计科1141学号:201411621110姓名:邓超荣实验一进程同步与互斥实验目的了解多进程并发执行时因控制不当而导致的运行结果不确定的竞争条件现象、以及消除竞争条件所采取的措施。实验内容有一个数据文件,名字是data,其中存放了一个十进制正整数。现有一个程序,该程序读出文件data中的数据、将其加一、再将结果更新到data之中,上述动作重复进行一百万次。如下给出完成上述功能的源程序:01#includestdio.h02#includestdlib.h03#includefcntl.h04#includesys/types.h05#includeunistd.h06#includestdarg.h07#includestring.h08intmain()09{10intnum,fd,i;//num变量用于存放从buff转换而来的二进制形式的整数//fd是打开data文件之后的描述符,用于下文对data文件的读写操作11charbuff[100];//定义的buff字符数组用于存放从文件中读出的数字字符形式的整数12fd=open(data,O_RDWR);//打开文件13if(fd=0){//如果文件不存在14printf(openerror\n);15return1;16}17for(i=1;i=1000000;i++){//循环一百万次循环循环18lseek(fd,0,SEEK_SET);//将文件的读写指针归零19intlen=read(fd,buff,100);//len存放从文件读入的数字符的长度20buff[len]='\0';//在字符串后添加空格代表结束21num=atoi(buff);//调用atoi函数,将字符串转换为二进制形式,并存放在num22sprintf(buff,%d\n,num+1);//num+1,循环10000次后就是1000000+num23lseek(fd,0,SEEK_SET);//将文件的读写指针归零即置于起始字节之处24write(fd,buff,strlen(buff));//将更新后的数重新写入文件中25}26close(fd);//关闭文件27return0;//返回28}问题:1.请在linux中编译、链接、执行这个程序。如果该程序只作为单个进程执行,请观察运行结果,并分析代码。首先向data文件中输入1107,并进行保存。该程序分析如下:第10行中定义变量num存放从buff的字符串中转换而来的二进制形式的整数,变量fd存放打开data文件之后的描述符;第11行中定义长度为100的字符数组,用于存放从data文件中读出的数字字符形式的整数;第12行打开data文件;第13-16行判断文件是否打开,如果没有,则输出openerror提示;第17-25行,循环1000000次操作,第18行,在每次循环都将文件的读写指针指向文件的起始位置;第19行,len保存读入字符串的长度;第20行,在字符串结尾加入空格符以示结束;第21行,调用atoi()函数,将buff的字符串转变为二进制数;第22行,对转变得二进制数进行+1操作;第23行,把文件的读写指针至于文件起始位置;第24行,将更新的数据重新写回data文件中。如此循环一百万次,相当于data中存放的数据加上一百万,所以得出图中所示结果。2.在不改变程序代码的情况下,怎样把上述程序作为多个进程来并发执行?请观察并发执行情况下的运行结果,分析运行结果错误的具体原因。答:要实现多进程并发执行,可多个窗口对同一程序进行运行。由于data文件初始值为1234,所以两个进程在并发执行的情况下,正确结果应该为2001234,可是最后结果却为1509625。显然与正确结果不符。此主要原因在于,在两个进程同时执行的时候,可能会在同一时间对num进行操作,导致重读,如原本进程1对2加1后为3,进程而对3加1后为4.而现实中可能产生的情况是进程1和进程2同时对2进行加1操作,所以得到最终结果是3而不是4;另一种情况是,进程1已进行了加1操作但在保存到文件之前,进程2执行到读取文件数据,因此,进程2读取的还是原本数据,进行加1操作后仍然是进程1执行操作后的数据。所以当多进程并发执行时,最后得出的结果与预想中的结果不同。3.请修改上述代码,采用上锁方式,以保证并发执行时运行结果的正确性,并分析得到了正确结果的原因。修改后,代码如下:#includestdio.h#includestdlib.h#includefcntl.h#includesys/types.h#includeunistd.h#includestdarg.h#includestring.hintmain(){structflockfl;//定义结构体flock,设置锁intnum,fd,i;charbuff[100];fd=open(data,O_RDWR);if(fd=0){printf(openerror\n);return1;}fl.l_whence=SEEK_SET;//设置文件读写位置fl.l_start=1;//开始位置为1fl.l_len=1;//长度为1fl.l_pid=getpid();//获取进程for(i=1;i=1000000;i++){fl.l_type=F_WRLCK;//对文件加锁fcntl(fd,F_SETLKW,&fl);//对文件逐个扫描lseek(fd,0,SEEK_SET);intlen=read(fd,buff,100);buff[len]='\0';num=atoi(buff);sprintf(buff,%d\n,num+1);lseek(fd,0,SEEK_SET);write(fd,buff,strlen(buff));fl.l_type=F_UNLCK;//解锁文件fcntl(fd,F_SETLKW,&fl);}close(fd);return0;}该程序分析结果如下:当进程1对文件进行操作时,对文件进行加锁,防止其他进程对文件同时操作,也就是,其他进程阻塞。当进程1完成操作对文件解锁后,进程2被唤醒,进而对文件进行操作,在操作前,同样对文件进行加锁。如此类推,对个进程交替执行,保证了结果的正确性。实验心得:写出你对单次执行和并发进程的感受,操作系统对并发进程控制的重要性。在数据量比较少的情况下,单次执行的速度比并发执行的速度占有一定的优势。但在数据量的达到百万上亿的时候,单次执行的速度明显不尽人意。而并发执行能多个进程同时对一个程序进行操作,就如,工厂里生产汽车零件,一个人一天的产量必定少于多个人的共同完成生产零件一个的产量。当然,物极必反,并不是说进程越多越好,当进程增多,就容易出现进程空闲的情况,导致性能的下降。操作系统每天都要处理庞大的数据,若使用单次执行方式,不单会导致系统运行速度慢,还会让使用者陷于崩溃的等待中,所以,操作系统对并发执行的应用与控制显得更重要。