操作系统实验报告_线程并发拷贝程序

合集下载

线程实验报告

线程实验报告

线程实验报告线程实验报告引言:线程是计算机科学中的一个重要概念,它是操作系统能够进行运算调度的最小单位。

线程的使用能够提高程序的并发性和响应性,使得程序能够更高效地利用计算机资源。

本次实验旨在通过编写一个简单的多线程程序,来探究线程的工作原理和应用。

实验目的:1. 了解线程的基本概念和特点;2. 掌握线程的创建、同步和销毁方法;3. 理解多线程编程的优势和挑战。

实验过程:1. 创建线程在实验开始时,我们首先需要创建线程。

在C++中,可以使用pthread库来实现。

通过调用pthread_create函数,我们可以创建一个新的线程,并将其与指定的函数进行绑定。

在实验中,我们创建了两个线程,分别执行不同的任务。

2. 线程同步在多线程编程中,线程之间的同步是一个重要的问题。

为了避免竞态条件和资源争用,我们需要使用互斥锁和条件变量等同步机制。

在本次实验中,我们使用了互斥锁来保护共享资源的访问,以及条件变量来实现线程之间的通信。

3. 线程销毁线程的销毁是一个关键的步骤。

在实验中,我们使用了pthread_join函数来等待线程的结束,并回收线程的资源。

这样可以确保线程的正确退出,避免资源泄漏和程序崩溃。

实验结果:通过实验,我们发现多线程编程具有以下优势:1. 提高程序的并发性:通过并行执行多个任务,可以提高程序的运行效率,减少等待时间。

2. 增强程序的响应性:多线程可以使程序具有更好的交互性,用户可以在任务执行的同时进行其他操作。

3. 充分利用计算机资源:多线程能够充分利用多核处理器的计算能力,提高系统的整体性能。

然而,多线程编程也存在一些挑战:1. 竞态条件:当多个线程同时访问共享资源时,可能会导致数据的不一致性和程序的错误。

2. 死锁和饥饿:线程之间的同步问题可能导致死锁和饥饿现象,使得程序无法正常执行。

3. 调试困难:多线程程序的调试比单线程程序更加困难,需要仔细分析线程之间的交互关系。

结论:通过本次实验,我们深入了解了线程的工作原理和应用。

操作系统实验报告3

操作系统实验报告3

步骤4:单击“Build”菜单中的“Compile 31.cpp”命令,并单击“是”按钮确认。系统对3-1.cpp 进行编译。 步骤5:编译完成后,单击“Build”菜单中 的“Build 3-1.exe”命令,建立3-1.exe可执行文件。 操作能否正常进行?如果不行,则可能的原因是 什么? 能 步骤6:在工具栏单击“Execute Program” (执行程 序) 按钮,执行3-1.exe程序。 运行结果 (分行书写。如果运行不成功,则可能的 原因是什么?) : 1) event created 2) child created 3) Parent waitichild processng on child. 4) beginning…… 5) event signaled
API名称 CreateEvent() OpenEvent() SetEvent() ResetEvent() PulseEvent() 表3-1 用于管理事件对象的API 描述 在内核中创建一个新的事件对象。此函数允许有安全性 设置、手工还是自动重置的标志以及初始时已接受还是未 接受信号状态的标志 创建对已经存在的事件对象的引用。此API函数需要名 称、继承标志和所需的访问级别 将手工重置事件转化为已接受信号状态 将手工重置事件转化为非接受信号状态 将自动重置事件对象转化为已接受信号状态。当系统释 放所有的等待它的线程时此种转化立即发生
源的线程应该在实际执行操作之前获得互斥体, 而在访问结束时立即释放互斥体,以允许下一个 等待线程获得互斥体,然后接着进行下去。 与事件对象类似,互斥体容易创建、打开、使用 并清除。利用CreateMutex() API可创建互斥体, 创建时还可以指定一个初始的拥有权标志,通过 使用这个标志,只有当线程完成了资源的所有的 初始化工作时,才允许创建线程释放互斥体。

上机实验指导(线程并发拷贝程序)

上机实验指导(线程并发拷贝程序)

《第四次上机实验指导(线程并发拷贝程序)》实验目的:设计线程并发拷贝程序和模拟管道文件的程序并上机编程实现,让学生自己动脑筋来思考课堂上讲述的内容,把主要知识系统化地串联起来,增加感性认识;加深理解系统的并发工作过程和原理;加深对线程的理解;加深对进程和线程之间同步互斥的理解;并增强编写并发程序的能力。

通过实验进一步强化学生的实际编程能力及分析问题、解决问题的能力。

实验内容及要求:编写线程并发拷贝程序,通过模拟管道文件的实现(管道定义、创建管道、读管道程序和写管道程序程序实现),实现同步互斥,检验程序运行结果。

实验前要认真预习课程上讲解的有关内容,完成数据结构设计、模块划分及程序流程图设计,第一次上机时要提交书面的设计报告(初稿),编写出主要程序。

4次上机(8学时)完成程序的修改完善及调试。

每次修改程序时都要对照书面设计报告进行修改,并在书面设计报告上留下修改记录,经过最后修改的书面设计报告要和正式的实验报告一并提交(编写的程序要和书面设计报告中画出的程序流程图基本一致)。

2次上机(4学时)进行程序的运行效果检验及源程序检查(对照书面设计报告进行讲解,接受提问)。

理解“图8 进程并发拷贝程序工作时各部件动作序列及进程状态变化图示片断”见后面的文章“操作系统课程教学研究(一)----核心内容的教学方法探讨”实验的参考资料及提示:(1)进程并发拷贝程序.doc#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#define BSIZE 512main(int argc,char *argv[]){int x,fdr,fdw,n,fdp[2];char abuf[BSIZE];fdr=open(argv[1],O_RDONL Y);fdw=open(argv[2],O_CREA T|O_RDWR,0777);pipe(fdp);while((x=fork())==-1);if(x==0){while((n=read(fdr,abuf,BSIZE))>0)write(fdp[1],abuf,n);}else{while((n=read(fdp[0],abuf,BSIZE))>0)write(fdw,abuf,n);}}(2)基本提示、把创建进程改为创建线程,把进程并发改为线程并发、上面程序中的pipe(fdp)(创建管道)不允许使用,要使用ppipe(fdp) (ppipe(、、、)是自己定义的函数,模拟管道文件的创建)。

操作系统实验报告_进程和线程

操作系统实验报告_进程和线程

回答思考题的答案)
一、进程的创建
下面这个C程序展示了UNIX系统中父进程创建子进程及各自分开活 动的情况。
实验指导
fork( ) 创建一个新进程。
系统调用格式:
参数定义:
pid=fork( )
int fork( ) fork( )返回值意义如下: 0:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是 子进程。
3、编译和运行
$gcc process.c –o processs
4、运行
$./process 程序运行截图
5、思考
(1) 系统是怎样创建进程的? (2) 扩展程序,在父进程中输出1到5,在子进程中输出6-
10,要求父子进程并发输出;记录实验结果,并给出简 单分析。
6.实验中遇到的问题和解决方法
fprintf(stderr, "Fork Failed"); exit(-1); } else if (pid == 0) { /* child process */ execlp( "/bin/ls", "ls",NULL); } else {/* parent process */ /* parent will wait for the child to complete */ wait(NULL); printf( "Child Complete" ); exit(0); } }
4、思考
(1)程序运行后,进程thread中有几个线程存在? (2)为什么前后两次运行结果不一样?
答(1) (2)
5.实验中遇到的问题和解决方法 运行结果并没有出现预期效果
2、参考程序代码
/*process.c*/

操作系统实验报告_线程并发拷贝程序

操作系统实验报告_线程并发拷贝程序

盛年不重来,一日难再晨。

及时宜自勉,岁月不待人。

操作系统:线程(进程)并发拷贝程序附录一:程序代码#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<pthread.h>#include<malloc.h>#define PSIZE 4096 /*管道文件的大小*/#define BSIZE 128 /*默认缓冲区的大小*/#define NOFILE 20 /*u_ofile3705表可分配的个数*/#define NFILE 20 /*file表可分配的个数*/#define NPIPE 20 /*pipecb3705可分配的个数*//*进程的u_file表*/int u_ofile3705[NOFILE];/*模拟file表*/struct{char f_flag;/*读写标志,'w'表示写,'r'表示读*/int f_count;/*表示此表项的状态,=0表示此表项没被使用,可分配;=1表示此表项在被使用,不可再分配*/int f_inode;/*对应的pipecb3705表下标*/long f_offset;/*读写指针,当前已读或已写个数*/}file[NFILE];/*管道控制块*/struct{char *p_addr;/*管道文件基地址*/int p_size;/*管道文件大小,PSIZE*/int p_count;/*=2表示读写都在被进行,=1表示在被读或被写,=0表示管道没被使用,可分配*/}pipecb3705[NPIPE];/*模拟管道文件*/char *pfile;/*管道的写入写出端*/int fd[2];/*锁机制,实现互斥*/pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;/*进程间通信,实现同步*/pthread_cond_t rflag = PTHREAD_COND_INITIALIZER;/*读信号量*/ pthread_cond_t wflag = PTHREAD_COND_INITIALIZER;/*写信号量*/ /*线程创建函数只能传一个参数,用结构体来封装所有参数*/struct arg_set{char *fname; /*文件名*/int f; /*传递fdp[]*/};/*u_ofile3705表初始化*/int u_ofile_init3705(){printf("init the u_ofile3705\n");int i;for(i=0;i<NOFILE;i++)u_ofile3705[i] = -1;u_ofile3705[0]=0;u_ofile3705[1]=0;u_ofile3705[2]=0;return 0;}/*创建管道*/int pipe_simulate3705(int a[]){printf("start to create a pipe\n");int i;for(i=0;i<NOFILE;i++){if(u_ofile3705[i]==-1){a[0] = i;/*读*/u_ofile3705[i] = 0;/*读端*/break;}}for(i;i<NOFILE;i++){if(u_ofile3705[i]==-1){a[1] = i;/*写*/u_ofile3705[i] = 1;/*写端*/break;}}if(i>=NOFILE){printf("u_ofile3705分配失败,failure to create a pipe\n");return -2;}pfile = (char *)malloc(PSIZE*sizeof(char));/*申请模拟管道用的内存空间*/ if(pfile==NULL)/*申请可能不成功*/{printf("failure to create a pipe\n");return -1;}for(i=0;i<NFILE;i++){if(file[i].f_count!=1){file[i].f_flag = 'r';/*读标志*///file[i].f_inode = 0;/*读对应pipecb3705表下标*/file[i].f_count = 1;/*file[0]这个表项在被使用,不可再分配*/file[i].f_offset = 0;/*读指针*/u_ofile3705[a[0]] = i;/*读端*/break;}}for(i=0;i<NFILE;i++){if(file[i].f_count!=1){file[i].f_flag = 'w';/*写标志*///file[i].f_inode = 0;/*写对应pipecb3705控制块下标*/file[i].f_count = 1;/*file[1]这个表项在被使用,不可再分配*/file[i].f_offset = 0;/*写指针*/u_ofile3705[a[1]] = i;/*写端*/break;}}if(i>=NFILE){printf("failure to create a pipe\n");return -1;}for(i=0;i<NPIPE;i++){if(pipecb3705[i].p_count==0){pipecb3705[i].p_addr = pfile;/*给管道文件基地址赋值*/pipecb3705[i].p_size = PSIZE;/*管道文件大小*/pipecb3705[i].p_count = 2;/*读写都在进行,此pipecb3705表项不可再分*/file[u_ofile3705[a[0]]].f_inode = i;file[u_ofile3705[a[1]]].f_inode = i;break;}}if(i>=NPIPE){printf("failure to create a pipe\n");return -1;}printf("Secceed create the pipe\n");return 0;/*分配成功*/}/*关闭管道*/int close_simulate3705(int a[]){printf("start to close the pipe you have created\n");char *p;int i;for(i=0;i<2;i++){p=pipecb3705[file[u_ofile3705[a[i]]].f_inode].p_addr;/*if(p!=NULL)free(p); //释放管道内存*/pipecb3705[file[u_ofile3705[a[i]]].f_inode].p_count = 0; /*管道控制块计数清零*/file[u_ofile3705[a[i]]].f_count = 0; /*file表项计数清零*/u_ofile3705[a[i]] = -1; /*u_ofile3705表项清空*/a[i] = -1; /*fdp[]清空?*/}printf("secceed close the pipe\n");return 0;}/*写管道*/int numwrite_simulate3705;int write_simulate3705(int fd,char *ca,int n)//将内存ca内容写入n个字符到管道fd里{printf("(memory---->pipe)input data in memory *ca into pipe\n");numwrite_simulate3705++;long offr,offw;/*读写指针,实际是读写字符个数*/int r;/*管道文件读端*/int m;/*若ca中的字符不能一次写完,m用来表示一次可写入的字符的最大数*/int w = u_ofile3705[fd];/*管道文件写端*/int pf = file[w].f_inode;/*读管道对应的pipecb3705表的下标*/int n1 = n;/*一次应该写入的字符个数*/int wstart = 0;/*计数器,写入字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找写管道对应的读管道的读端*/{if((file[i].f_flag=='r')&&(file[i].f_inode==pf)){r = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if((offw+n1-PSIZE)>offr)/*不能一次写完*/{if(pipecb3705[pf].p_count==0)/*对文件的复制操作已进行结束,管道文件被释放*/ {printf("对文件的复制操作已进行结束,管道文件被释放\n");return 0;}else{m = PSIZE+offr-offw;/*最多可写入数*/for(wstart=0;wstart<m;wstart++){*(pipecb3705[pf].p_addr+offw%PSIZE) = *ca;ca++;offw++;}file[w].f_offset = offw;/*重定位写指针位置*/n1 = n1-m;/*剩余需要读的字符个数*/printf("weak up the read thread , pipe is readable\n");pthread_cond_signal(&rflag);/*唤醒读线程,管道可读*/printf("write thread is blocked and under the statement of waiting\n");pthread_cond_wait(&wflag,&lock);/*写线程封锁等待*/}}/*一次性可将ca中内容全部写入管道*/offr = file[r].f_offset;offw = file[w].f_offset;for(wstart=0;wstart<n1;wstart++){/*printf("%d\n",pipecb3705[pf].p_addr);*/*(pipecb3705[pf].p_addr+offw%PSIZE) = *ca;/*printf("%d\n",wstart);*/ca++;offw++;}file[w].f_offset = offw;pthread_cond_signal(&rflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (memory---->pipe)input data in memory *ca into pipe\n");return n;/*返回写入字符个数*/}/*读管道*/int numread_simulate3705;//read_simulate3705 diaoyongshuint read_simulate3705(int fd,char *ca,int n)//将管道fd内容读取n个字符到内存ca里{printf("(pipe---->memory)output data from pipe into memory *ca\n");numread_simulate3705++;long offr,offw;/*读写指针,实际是读写字符个数*/int w;/*管道文件写端*/int m;/*若ca中的字符不能一次读完,m用来表示一次可读出的字符的最大数*/ int r = u_ofile3705[fd];/*管道文件读端*/int pf = file[r].f_inode;/*读管道对应的pipecb3705表的下标*/int rstart = 0;/*计数器,读出字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找读管道对应的读管道的端*/{if((file[i].f_flag=='w')&&(file[i].f_inode==pf)){w = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if(offr==offw)/*管道空,无内容可读*/{printf("pipe is empty , nothing to output\n");if(pipecb3705[pf].p_count==1)/*写端关闭*/{pipecb3705[pf].p_count--;/*文件的复制以完成,释放管道文件的空间*/printf("the write point is closed,the copy of the file is finished\n");return 0;}else{printf("weak up the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);/*唤醒写线程,管道可写*/printf("read thread is blocked and under the statement of waiting\n");pthread_cond_wait(&rflag,&lock);/*读线程封锁等待*/}}offr = file[r].f_offset;offw = file[w].f_offset;m = n<=(offw-offr)?n:(offw-offr);/*得到可读字符个数*/for(rstart=0;rstart<m;rstart++){*ca = *(pipecb3705[pf].p_addr+offr%PSIZE);ca++;offr++;}file[r].f_offset = offr;/*重定位读指针位置*/printf("weak the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (pipe---->memory)output data from the pipe into memory *ca\n");return m;}/*线程调用,读源文件,写管道*/void *pwrite3705(void *a)//将源文件a内容写入管道中{printf("(file---->pipe)input data from the original file into pipe\n");char abuf1[BSIZE];struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/int fdr;int n_r;/*管道文件写入字符数*/if((fdr=open(args->fname,O_RDONL Y))!=-1){while((n_r=read(fdr,abuf1,BSIZE))>0)/*读文件,写管道*/{printf("(file---->memory)input data in original file into memory *ca\n");printf("Secceed (file---->memory)input data in original file into memory *ca\n");//printf("(memory---->pipe)input data in memory *ca into pipe\n");write_simulate3705(args->f,abuf1,n_r);//printf("Secceed (memory---->pipe)input\n");}pipecb3705[file[u_ofile3705[args->f]].f_inode].p_count--;/*文件已读完,关闭管道写端*/}else{perror(args->fname);/*打开源文件可能不成功*/return NULL;}printf("Secceed (file---->pipe)input data from the original file into pipe\n");return NULL;}/*线程调用,写目标文件,读管道*/void *pread3705(void *a)//读取管道,将其中内容写入新建文件中{printf("(pipe---->file)output data from the pipe into new file\n");char abuf2[BSIZE];/*缓冲区*/struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/int fdw;int n_w;/*管道文件读出字符数*/if((fdw=open(args->fname,O_CREAT|O_RDWR,0777))!=-1){while((n_w=read_simulate3705(args->f,abuf2,BSIZE))>0)/*读管道,写文件*/{//printf("(pipe---->memory)output data from pipe into memory *ca\n");//printf("Secceed (pipe---->memory)output data from pipe into memory *ca\n");printf("(memory---->file)output data in memory *ca into file\n");write(fdw,abuf2,n_w);printf("Secceed (memory---->file)output data from the pipe into new file\n");}}else{perror(args->fname);/*打开目标文件可能出错*/return NULL;}printf("Secceed (pipe---->file)output data from the pipe into new file\n");return NULL;}/*主函数*/int main(int argc,char *argv[]){int x;u_ofile_init3705();while((x=pipe_simulate3705(fd))==-1);/*创建管道,即申请空间*/if(x==-2)return -1;pthread_t t;//thread IDstruct arg_set args[2];/*用结构体传写线程需要的参数:文件名,管道文件读写端*/args[0].fname=argv[1];/*源文件名*/args[0].f=fd[1];/*管道文件写端*/args[1].fname=argv[2];/*目标文件名*/args[1].f=fd[0];/*管道文件读端*/pthread_create(&t,NULL,pwrite3705,(void *)&args[0]);/*创建子线程,写管道*/pread3705((void *)&args[1]);/*主线程调用,读管道*/pthread_join(t,NULL);/*等待写线程结束*/close_simulate3705(fd);printf("\nnum of read_simulate3705 = %d\n",numread_simulate3705);printf("num of write_simulate3705 = %d\n",numwrite_simulate3705);return 0;}附录二(实验结果):ls -l总用量2379-rw-r--r-- 1 john john 50 2012-12-17 18:06 3705-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3705.doc -rw-r--r-- 1 john john 95441 2012-08-27 22:16 3705.JPG -rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3705.mp3 -rw-r--r-- 1 john john 84835 2012-07-11 13:22 3705.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3705.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3705.rar-rw-r--r-- 1 john john 0 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cpp./tc 3705 a3705 > copy1./tc 3705 a3705.doc./tc 3705.doc a3705.doc./tc 3705.ppt a3705.ppt./tc 3705.mp3 a3705.mp3./tc 3705.rar a3705.rar > copy2./tc 3705.pdf a3705.rarls -l总用量5163-rw-r--r-- 1 john john 50 2012-12-17 18:06 3705-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3705.doc -rw-r--r-- 1 john john 95441 2012-08-27 22:16 3705.JPG -rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3705.mp3 -rw-r--r-- 1 john john 84835 2012-07-11 13:22 3705.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3705.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3705.rar-rwxr-xr-x 1 john john 50 2012-12-17 22:51 a3705-rwxr-xr-x 1 john john 36864 2012-12-17 22:51 a3705.doc -rwxr-xr-x 1 john john 95441 2012-12-17 22:53 a3705.JPG -rwxr-xr-x 1 john john 2083969 2012-12-17 22:54 a3705.mp3 -rwxr-xr-x 1 john john 84835 2012-12-17 22:56 a3705.pdf -rwxr-xr-x 1 john john 73728 2012-12-17 22:53 a3705.ppt -rwxr-xr-x 1 john john 19924 2012-12-17 22:55 a3705.rar -rw-r--r-- 1 john john 1320 2012-12-17 22:51 copy1-rw-r--r-- 1 john john 419294 2012-12-17 22:56 copy2-rw-r--r-- 1 john john 690 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 0 2012-12-17 22:57 sta2-rwxr-xr-x 1 john john 12256 2012-12-17 22:50 tc-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cppcat copy1init the u_ofilestart to create a pipe共享知识分享快乐Secceed create the pipe(pipe---->file)output data from the pipe into new file(pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputweak up the write thread , make the pipe writableread thread is blocked and under the statement of waiting(file---->pipe)input data from the original file into pipe(file---->memory)input data in original file into memory *ca Secceed (file---->memory)input data in original file into memory *ca (memory---->pipe)input data in memory *ca into pipe----add the lock----release the lockSecceed (memory---->pipe)input data in memory *ca into pipe Secceed (file---->pipe)input data from the original file into pipe weak the write thread , make the pipe writable----release the lockSecceed (pipe---->memory)output data from the pipe into memory *ca (memory---->file)output data in memory *ca into fileSecceed (memory---->file)output data from the pipe into new file (pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputthe write point is closed,the copy of the file is finishedSecceed (pipe---->file)output data from the pipe into new filestart to close the pipe you have createdsecceed close the pipenum of readp = 2num of writep = 1卑微如蝼蚁、坚强似大象。

线程并发实验报告

线程并发实验报告

一、实验目的1. 理解线程的概念和并发编程的基本原理。

2. 掌握线程的创建、同步和通信方法。

3. 通过实验加深对线程并发编程的理解,提高编程能力。

二、实验环境1. 操作系统:Windows 102. 开发工具:Visual Studio 20193. 编程语言:C++三、实验内容本次实验主要涉及以下内容:1. 线程的创建与销毁2. 线程的同步与互斥3. 线程的通信4. 线程池的使用四、实验步骤1. 线程的创建与销毁(1)创建线程:使用C++11标准中的`std::thread`类创建线程。

```cpp#include <iostream>#include <thread>void threadFunction() {std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;}int main() {std::thread t1(threadFunction);std::thread t2(threadFunction);t1.join(); // 等待线程t1结束t2.join(); // 等待线程t2结束return 0;}```(2)销毁线程:线程会在任务执行完毕后自动销毁,无需手动销毁。

2. 线程的同步与互斥(1)互斥锁:使用`std::mutex`类实现线程间的互斥。

```cpp#include <iostream>#include <thread>#include <mutex>std::mutex mtx;void threadFunction() {mtx.lock();std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;mtx.unlock();}int main() {std::thread t1(threadFunction);t1.join();t2.join();return 0;}```(2)条件变量:使用`std::condition_variable`类实现线程间的条件同步。

操作系统课程实验报告

操作系统课程实验报告

一、实验概述实验名称:操作系统课程实验实验目的:1. 理解操作系统基本概念、原理及功能;2. 掌握操作系统的基本操作和应用;3. 提高实际操作能力和分析问题、解决问题的能力。

实验内容:1. 操作系统基本概念及原理的学习;2. 操作系统基本操作的应用;3. 实验项目:文件读写、多进程、多线程。

二、实验环境操作系统:Windows 10编译器:Visual Studio语言:C/C++实验平台:Windows 10系统下的虚拟机三、实验过程1. 操作系统基本概念及原理的学习操作系统是计算机系统中最基本的系统软件,负责管理计算机硬件资源、提供用户接口以及执行各种应用程序。

在实验过程中,我们学习了以下基本概念及原理:(1)进程管理:进程是操作系统能够进行运算处理的独立单位,具有动态性、并发性、异步性和独立性等特点。

进程管理主要包括进程的创建、调度、同步、通信和终止等。

(2)内存管理:内存管理是操作系统核心功能之一,主要负责分配、回收、保护和管理内存资源。

内存管理方式有分页、分段、段页式等。

(3)文件系统:文件系统是操作系统用于存储、检索和管理文件的机制。

文件系统主要包括目录结构、文件属性、文件操作等。

(4)设备管理:设备管理负责管理计算机系统中的各种外部设备,包括输入、输出和存储设备。

设备管理主要包括设备分配、设备驱动程序、缓冲区管理等。

2. 操作系统基本操作的应用在实验过程中,我们应用以下基本操作:(1)进程管理:创建、调度、同步、通信和终止进程。

(2)内存管理:分配、回收、保护和管理内存资源。

(3)文件系统:创建、删除、读写文件,实现目录结构的管理。

(4)设备管理:分配、回收、控制和管理设备。

3. 实验项目:文件读写、多进程、多线程(1)文件读写实验实验目的:掌握文件的基本操作,实现文件的创建、打开、读取、写入和关闭。

实验步骤:① 创建一个文件,命名为“test.txt”。

② 打开文件,以读写模式。

多线程拷贝实验报告

多线程拷贝实验报告

#### 一、实验目的1. 理解多线程在文件拷贝过程中的应用。

2. 掌握使用多线程提高文件拷贝效率的方法。

3. 学习线程同步与互斥机制在文件拷贝中的应用。

4. 评估多线程拷贝程序的性能与单线程拷贝程序的性能差异。

#### 二、实验环境- 硬件:个人笔记本电脑- 软件:Windows操作系统,Java Development Kit (JDK) 1.8及以上版本#### 三、实验内容本次实验主要涉及以下内容:1. 创建一个简单的单线程文件拷贝程序。

2. 设计并实现一个多线程文件拷贝程序。

3. 比较单线程与多线程文件拷贝程序的性能。

4. 分析线程同步与互斥在文件拷贝中的作用。

#### 四、实验步骤1. 单线程文件拷贝程序- 编写一个简单的Java程序,用于读取源文件内容,并将内容写入目标文件。

- 使用`FileInputStream`和`FileOutputStream`进行文件的读写操作。

2. 多线程文件拷贝程序- 将文件分割成多个部分,每个线程负责拷贝文件的一个部分。

- 使用`Runnable`接口创建多个线程,并使用`ExecutorService`来管理线程。

- 在每个线程中,使用`FileInputStream`和`FileOutputStream`分别读取和写入文件的一部分。

- 使用`CountDownLatch`确保所有线程完成拷贝后再关闭文件流。

3. 性能比较- 对比单线程与多线程文件拷贝程序在相同文件大小下的拷贝时间。

- 分析多线程程序中线程数量对性能的影响。

4. 线程同步与互斥- 分析在多线程文件拷贝过程中,如何使用同步与互斥机制保护共享资源。

- 实现互斥锁(`ReentrantLock`)来保护文件读写操作,防止数据竞争。

#### 五、实验结果与分析1. 单线程文件拷贝- 程序能够正确完成文件拷贝任务。

- 拷贝速度受限于CPU和硬盘性能。

2. 多线程文件拷贝- 多线程程序能够显著提高文件拷贝速度。

程序并发执行实验报告

程序并发执行实验报告

一、实验目的1. 理解并发执行的概念和原理。

2. 掌握多线程编程的基本方法。

3. 学会使用同步机制解决并发编程中的竞争条件。

4. 分析并发程序的性能和效率。

二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 创建一个简单的并发程序,实现两个线程同时执行。

2. 使用同步机制解决并发程序中的竞争条件。

3. 分析并发程序的性能和效率。

四、实验步骤1. 创建一个简单的并发程序(1)创建一个名为ConcurrentTest的类,该类继承自Thread类。

(2)在ConcurrentTest类的run方法中,打印出当前线程的名字。

(3)在主函数中,创建两个ConcurrentTest对象,分别命名为thread1和thread2。

(4)启动thread1和thread2线程。

(5)等待thread1和thread2线程执行完毕。

2. 使用同步机制解决并发程序中的竞争条件(1)创建一个名为Counter的类,该类包含一个私有变量count和一个静态同步方法add。

(2)在add方法中,增加count变量的值。

(3)在主函数中,创建一个Counter对象counter。

(4)创建两个线程,分别调用counter对象的add方法。

(5)启动两个线程,并等待它们执行完毕。

3. 分析并发程序的性能和效率(1)在主函数中,记录两个线程开始执行的时间。

(2)在主函数中,记录两个线程执行完毕的时间。

(3)计算两个线程执行所需的时间差。

五、实验结果与分析1. 实验结果(1)简单的并发程序在控制台中,可以看到thread1和thread2线程交替打印出它们的名字。

(2)使用同步机制解决竞争条件在控制台中,可以看到Counter对象的count变量值正确地增加了。

(3)分析并发程序的性能和效率thread1和thread2线程执行所需的时间差为0.01秒。

2. 实验分析(1)简单的并发程序通过创建两个线程,实现了两个任务同时执行。

操作系统线程同步机制实验报告

操作系统线程同步机制实验报告

操作系统线程同步机制实验报告一、实验目的本实验旨在通过对操作系统线程同步机制的实验,深入了解操作系统中线程的运行和同步原理,掌握线程同步机制的使用方法以及安全性问题。

二、实验背景在操作系统中,线程是实现多任务并发执行的基本单位。

为了确保线程的安全性,避免出现竞态条件等问题,需要采取合适的线程同步机制。

三、实验内容1.实现基本的线程同步操作通过使用互斥锁和条件变量,实现以下线程同步问题:(1)生产者/消费者问题:生产者线程生产一定数量的产品,消费者线程从缓冲区中取出产品并消费。

(2)读者/写者问题:多个读者线程可以同时读取共享资源,但是写者线程获取写权限后,其他线程无法读取或写入。

2.实验操作步骤(1)设计和实现多线程程序,包括生产者线程、消费者线程、读者线程和写者线程。

(2)使用互斥锁和条件变量对共享资源进行同步操作,保证线程的安全性。

(3)编译并运行程序,观察线程的执行顺序和结果是否符合预期。

四、实验结果与分析1.生产者/消费者问题通过设计合适的缓冲区和互斥锁,保证生产者线程和消费者线程的安全访问。

实验结果表明,生产者线程可以正确地生产产品,并将产品存储到缓冲区中。

消费者线程可以从缓冲区中取出产品并消费。

2.读者/写者问题通过使用互斥锁和条件变量,实现多个读者线程可以同时读取共享资源,但是写者线程获取写权限后,其他线程无法读取或写入。

实验结果表明,读者线程可以同时读取共享资源,而写者线程获取写权限后,其他线程无法读取或写入。

五、实验总结本实验通过对操作系统线程同步机制的实验,深入了解了操作系统中线程的运行和同步原理,掌握了线程同步机制的使用方法以及安全性问题。

实验结果表明,在设计合适的缓冲区和使用适当的同步机制的情况下,可以有效地保证线程的安全性和正确的并发执行。

六、实验心得通过本次实验,我深刻理解了线程同步机制在操作系统中的重要性。

线程同步机制可以保证多个线程正确地访问共享资源,避免竞态条件等问题的出现。

操作系统实验报告 并发程序设计

操作系统实验报告 并发程序设计

《计算机操作系统》实验报告(一)学号:030702412 姓名:陈楠学院:数计学院专业:计算机类年级:2007级班级:4班实验时间:2009-2010学年第一学期指导教师:丁善镜、黄志华目录1、实验题目 (3)2、实验目的 (3)3、实验环境 (3)4、实验原理 (3)5、实验内容 (3)5.1、fork()函数机理探索 (3)5.1.1、原始代码段 (3)5.1.2、代码段修改一 (3)5.1.3、结论(1) (4)5.1.4、fock()函数原理 (4)5.1.5、代码段修改二 (4)5.2、并发执行测猜测 (5)5.2.1、并发执行改进 (5)5.2.2、代码段修改(3) (5)5.3、小结 (6)1、实验题目2、实验目的掌握在程序中创建新进程的方法,观察并理解多道程序并发执行的现象。

3、实验环境Red Hat Enterprise Linux 54、实验原理fork():建立子进程。

子进程得到父进程地址空间的一个复制。

返回值:成功时,该函数被调用一次,但返回两次,fork()对子进程返回0,对父进程返回子进程标识符(非0值)。

不成功时对父进程返回-1,没有子进程。

5、实验内容分析一下程序运行时其输出结果有哪几种可能性,然后实际调试该程序观察其实际输出情况,比较两者的差异,分析其中的原因。

5.1、fork()函数机理探索5.1.1、原始代码段#include<stdio.h>#include<unistd.h>void main (void){ int x=5;if( fork( ) ){x+=30;printf (“%d\n”,x);}elseprintf(“%d\n”,x);printf(“%d\n”,x);}为了了解fork()函数的机理,了解fork()是从哪里开始重复执行代码,特将代码做了第一次修改5.1.2、代码段修改一#include<stdio.h>#include<unistd.h>图1 验证fork()函数原理 图2 验证是否共享内存 void main (void){ int x=5;printf(“start \n”);if( fork( ) ){x+=30;printf (“father %d \n”,x);}elseprintf(“child %d \n”,x);printf(“out%d \n”,x);}右侧为第一次修改后代码的输出(图1)5.1.3、 结论(1)fock() 对于该语句之前的程序段只执行一次fock() 对于该语句返回两次值,并针对两次返回值依次执行之后的语句5.1.4、 fock()函数原理 被fork 创建的新进程叫做自进程。

多线程并发实验报告

多线程并发实验报告

一、实验目的1. 理解多线程并发编程的基本概念和原理;2. 掌握Java多线程编程的基本方法和技巧;3. 学习线程同步机制,解决线程安全问题;4. 熟悉线程调度策略,提高程序性能。

二、实验环境1. 操作系统:Windows 102. 开发工具:IntelliJ IDEA3. JDK版本:1.8三、实验内容1. 线程创建与启动2. 线程同步与互斥3. 线程通信与协作4. 线程池与线程调度5. 线程局部变量与共享变量四、实验步骤及结果分析1. 线程创建与启动实验步骤:(1)创建一个继承自Thread类的子类;(2)重写run()方法,定义线程的执行逻辑;(3)创建Thread对象,并调用start()方法启动线程。

实验结果:成功创建并启动两个线程,分别执行各自的run()方法。

2. 线程同步与互斥实验步骤:(1)创建一个共享资源;(2)使用synchronized关键字声明同步方法或同步代码块;(3)在同步方法或同步代码块中访问共享资源。

实验结果:线程在访问共享资源时,能够保证互斥,防止数据不一致。

3. 线程通信与协作实验步骤:(1)使用wait()和notify()方法实现线程间的通信;(2)创建共享对象,作为线程间通信的媒介;(3)在等待线程中调用wait()方法,在通知线程中调用notify()方法。

实验结果:线程能够通过wait()和notify()方法实现通信与协作,完成特定任务。

4. 线程池与线程调度实验步骤:(1)使用Executors工厂方法创建线程池;(2)提交任务到线程池;(3)关闭线程池。

实验结果:线程池能够有效地管理线程,提高程序性能。

5. 线程局部变量与共享变量实验步骤:(1)创建线程局部变量;(2)创建共享变量;(3)在各个线程中访问和修改线程局部变量与共享变量。

实验结果:线程局部变量在各个线程中独立存在,不会相互干扰;共享变量在各个线程中共享,需要使用同步机制保证数据一致性。

操作系统实验报告

操作系统实验报告

操作系统实验报告
班级:
姓名:
学号:
实验一
实验内容:获得当前系统中正在运行的所有进程的优先级
实验目的:通过该实验,掌握查找系统中正在运行的进程的API,同时加深对进程优先级的了解。

试验方法:通过CreateToolhelp32Snapshot函数获得系统中正在运行的进程的快照,再通过PROCESSENTRY32结构逐个获取并输出快照中进程的ID与优先级。

实验流程
实验结果:
实验二
实验内容:使用互斥对象实现线程同步
实验目的:了解windows线程的并发性,以及线程同步的必要性,并通过该实验来了解线程的同步机制。

实验方法:通过CreateMutex创建互斥对象,然后利用同一互斥对象
在某一时刻只能被一个线程所访问来实现线程之间的同步性。

实验流程:
实验结果:
实验三
实验内容:使用文件映射对象实现线程间同步
实验目的:通过分析th8.cpp,掌握线程之间文件映射的通信方式以及关键的API。

实验方法:通过使用INV ALID_HANDLE_V ALUE的CreateFileMapping来创建一临时的内存映射文件,供线程间通信。

通过互斥对象以及sleep延时来实现线程同步。

实验流程:
实验结果:。

操作系统--进程和线程实验报告

操作系统--进程和线程实验报告

一.进程的创建1.编辑源程序。

2. 编辑结果如下。

3.编译和运行程序。

4.运行解释结果在语句p1=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了.这两个进程的几乎完全相同,将要执行的下一条语句都是if(p1==0). 而fork函数有三种返回值。

(1)在父进程中,fork返回新创建子进程的进程ID;(2)在子进程中,fork返回0;(3)如果出现错误,fork返回一个负值;所以,子进程中p1==0,输出I am child。

父进程p1>0,输出I am parent。

1.编辑源程序。

2.编辑结果如下。

3.编译和运行程序。

4. 运行解释结果在语句p1=fork()之前,只有父进程执行,putchar(‘x’)语句将x放入父进程的缓冲区。

当成功创建子进程后,子进程复制父进程的缓冲区。

接着子进程运行输出xby,父进程输出xay。

1.编辑源程序。

2.编辑结果如下。

3.编译和运行程序。

4. 运行解释结果在语句p1=fork()之前,只有父进程执行,putchar(‘x’)语句将x放入父进程的缓冲区。

当成功创建子进程后,子进程复制父进程的缓冲区。

接着子进程输出b后,执行exit(0)系统调用终止执行。

父进程输出a 后继续输出y。

所以父进程输出xay而子进程输出xb。

1.编辑源程序。

2.编辑结果如下。

3.编译和运行程序。

4. 运行解释结果语句while(p1=fork()==-1)创建了子进程和父进程。

父进程执行到wait()时,等待子进程的终止信号,当子进程执行完exit(0)后,父进程才继续执行。

实现了父进程等待子进程。

1.编辑源程序。

2.编辑结果如下。

child.cchild_parent.c3. 编译和运行程序。

4. 运行解释结果语句while(p1=fork()==-1)创建了子进程和父进程。

父进程执行wait(0)等待子进程的终止信号。

子进程加载child程序,输出I am a child。

操作系统实验报告

操作系统实验报告

操作系统实验报告1. 实验目的本实验旨在通过设计和实现一个基本的多道批处理操作系统来加深对操作系统基本概念和原理的理解,并加强对操作系统进行实践的能力。

2. 实验环境本实验采用如下环境进行实验:•操作系统:Windows 10•编程语言:C3. 实验内容本实验实现了一个基本的多道批处理操作系统,主要包括以下内容:3.1 进程调度操作系统通过进程调度算法,根据进程的优先级和进程的执行状态来决定下一次运行的进程,从而合理利用和分配CPU资源。

本实验中我们采用了基本的抢占式调度算法,即优先级越高的进程将会获得更多的CPU时间。

3.2 进程管理操作系统管理着多个并发运行的进程,在系统的执行过程中需要对这些进程进行管理,如创建新进程、销毁进程、挂起进程等等。

本实验中我们实现了进程的创建和销毁功能,并可以通过调用相应系统调用来挂起和恢复进程。

3.3 内存管理操作系统需要管理系统中的内存空间,为各个进程分配所需的内存。

本实验中我们实现了基本的内存管理功能,可以为进程分配内存空间,并在进程结束时回收内存资源。

3.4 文件管理操作系统能够管理文件系统,在文件系统中进行文件的创建、读取、写入和删除等操作。

本实验中我们实现了文件管理功能,可以创建和删除文件,并实现了文件的读写操作。

4. 实验结论通过本次实验,我们深入学习了操作系统的基本原理和概念,并实践了设计和实现一个基本的多道批处理操作系统。

通过实验,我们掌握了进程调度、进程管理、内存管理和文件管理等基本功能的实现方法。

在实现的过程中,我们发现操作系统的设计与实现是非常复杂且需要考虑多种因素的。

通过本次实验,我们对操作系统的工作原理有了更加深入的理解,并提升了解决问题和编程能力。

5. 实验总结通过本次实验,我们进一步了解了操作系统的工作原理和基本功能,并通过设计和实现一个基本的多道批处理操作系统来加深对操作系统的理解。

在实验过程中,我们遇到了一些问题,如进程调度算法的选择、内存资源的分配等等。

实习报告:软件开发中的多线程与并发编程

实习报告:软件开发中的多线程与并发编程

实习报告:软件开发中的多线程与并发编程一、引言在当今的软件开发领域中,多线程和并发编程是一种非常重要的技术。

随着计算机硬件的飞速发展和多核处理器的普及,利用多线程来实现并发处理已成为提高软件性能和响应能力的关键技术之一。

本实习报告将围绕多线程和并发编程的基本概念、原理以及实践经验展开讨论。

二、多线程与并发编程的基本概念1. 多线程概述在计算机科学中,线程是指在进程中独立执行的最小单位。

多线程即同时运行多个线程,每个线程独立执行指定的任务。

与传统的单线程顺序执行相比,多线程可以充分利用计算机多核心的优势,通过并行执行来提高系统的整体性能。

2. 并发编程概述并发编程是指能够同时处理多个任务的能力。

在软件开发中,通过利用并发编程可以实现资源的共享和充分利用,提高系统的并发能力和吞吐量。

同时,并发编程也能够提高用户体验,使得程序在执行任务时能够实时响应用户的操作。

三、多线程与并发编程的原理和实践1. 多线程的原理多线程的原理包括线程的创建、上下文切换和线程同步。

线程的创建通过系统调用或通过线程池来实现。

上下文切换是指在多线程执行时,从一个线程切换到另一个线程的过程。

线程同步用于解决多个线程之间的数据共享与竞争问题,常见的线程同步方式包括锁、信号量、条件变量等。

2. 并发编程的实践经验在进行并发编程时,需要考虑以下几个方面:(1) 线程安全性:多个线程同时访问共享数据时,可能会引发数据竞争和内存一致性问题。

针对这些问题,可以采用加锁、使用原子操作等手段来保证线程的安全性。

(2) 死锁与活锁:当多个线程同时请求资源,但资源分配不当时,可能会导致死锁或活锁的发生。

避免死锁的方法包括避免循环等待、按照固定的顺序获取锁等。

(3) 资源管理:在并发编程中,资源的管理非常重要。

及时释放资源、避免资源泄露是保证程序健壮性的关键。

(4) 性能调优:合理地使用多线程可以提高软件的性能,但是过多或不合理的线程使用会带来资源浪费和性能下降。

操作系统实验报告

操作系统实验报告

操作系统实验报告操作系统是计算机科学中十分重要的一门课程,本次实验是关于操作系统的,通过实验,我们可以更深入地了解操作系统的相关知识和操作。

本篇文章将着重介绍本次操作系统实验的内容和实验过程中的收获。

一、实验内容本次实验内容主要涉及操作系统的进程、线程和进程同步三部分。

具体内容包括:1. 进程的创建和管理2. 线程的创建和管理3. 进程同步的实现在实验过程中,我们将分别使用C语言和Linux操作系统实现上述功能。

二、实验过程1. 进程的创建和管理在这一部分实验中,我们要创建多个进程,实现进程的调度和管理功能。

我们采用了Linux系统下的fork()函数,用于创建子进程。

在程序运行时,首先创建一个父进程,然后使用fork()函数创建四个子进程,每个子进程都有自己的进程号(pid),并在屏幕上输出该进程号以示区分。

为了实现进程的调度功能,我们在代码中加入了sleep()函数,用于将进程挂起一段时间,然后再轮流执行其他进程。

2. 线程的创建和管理在这一部分实验中,我们使用了C语言的POSIX线程库pthread.h,实现多线程的功能。

同样地,我们采用了Linux系统下的fork()函数来创建线程。

在代码运行时,我们创建了两个线程,并在屏幕上输出线程号(tid)以示区分。

为了实现线程的调度和管理功能,我们在代码中加入了pthread_join()函数,用于等待线程的执行完成。

3. 进程同步的实现在这一部分实验中,我们使用了Linux系统下的进程同步工具——信号量(semaphore)。

在代码中,我们使用sem_init()函数创建信号量,使用sem_wait()函数阻塞进程或线程,使用sem_post()函数释放进程或线程。

为了更好地理解信号量的工作原理,我们将代码分为生产者和消费者两部分,其中生产者用于向缓冲区添加数据,消费者则用于删除数据。

在这个过程中,我们需要使用信号量控制生产者和消费者的数量,避免出现生产过多或消费过多的情况。

操作系统多线程并发实验心得

操作系统多线程并发实验心得

操作系统多线程并发实验心得一、实验背景和目的操作系统是计算机系统中最基础的软件之一,它负责管理计算机硬件资源,为应用程序提供必要的服务。

多线程并发是操作系统中一个重要的概念,它能够提高计算机系统的效率和性能。

本次实验旨在通过编写多线程并发程序,加深对操作系统多线程并发原理的理解,并掌握相关技术。

二、实验环境和工具本次实验使用的操作系统是 Windows 10,开发工具是 Visual Studio 2019。

三、实验内容和步骤1. 实验一:创建多线程并发程序首先,我们需要创建一个多线程并发程序。

具体步骤如下:(1)打开 Visual Studio 2019,选择“新建项目”,选择“Windows 控制台应用程序”。

(2)在“解决方案资源管理器”中右键单击“源文件”,选择“添加” -> “新建项”,创建一个名为“MultiThread.cpp”的源文件。

(3)在 MultiThread.cpp 中编写代码。

代码如下:#include <iostream>#include <thread>#include <chrono>using namespace std;void threadFunc(int id){for (int i = 0; i < 5; i++){cout << "Thread " << id << " is running..." << endl;this_thread::sleep_for(chrono::seconds(1));}}int main(){thread t1(threadFunc, 1);thread t2(threadFunc, 2);t1.join();t2.join();return 0;}(4)编译并运行程序。

可以看到两个线程交替执行,每个线程输出五次。

软件开发实习报告:多线程并发编程的实践与总结经验分享

软件开发实习报告:多线程并发编程的实践与总结经验分享

软件开发实习报告:多线程并发编程的实践与总结经验分享一、引言在软件开发过程中,多线程并发编程是一个非常重要的概念。

它可以提高程序的执行效率,实现任务的并行处理,提升系统的响应速度。

因此,在软件开发实习中,我选择了多线程并发编程作为我的主要实践项目。

本篇报告将结合我的实践经验,分享我对多线程并发编程的理解和总结。

二、实践项目介绍在我的软件开发实习中,我参与了一个网络爬虫的开发项目。

该项目的主要目标是从互联网上获取大量的数据,并进行存储和分析。

由于需要处理大量的数据和任务,单线程的处理方式显然效率低下。

因此,我们决定采用多线程并发编程来优化程序的执行效率。

三、多线程并发编程的基本概念1. 线程线程是程序中独立运行的基本单位,它可以并发执行,共享进程的资源。

一个进程中可以包含多个线程,线程之间可以共享内存空间,相互之间可以通过共享内存进行通信。

2. 并发并发是指多个任务在同一时间段内同时执行的能力。

在多线程并发编程中,通过创建多个线程来实现程序的并发执行,提高程序的执行效率。

3. 线程同步由于多个线程共享同一份数据,可能会产生数据竞争的问题。

为了保证数据的一致性和正确性,需要使用线程同步机制来协调各个线程的执行。

常用的线程同步机制有互斥锁、条件变量、信号量等。

四、多线程并发编程的实践与总结1. 多线程任务的划分与执行在我们的网络爬虫项目中,我们将爬取数据的任务划分为多个独立的子任务,并由不同的线程负责执行。

通过合理的任务划分和线程分配,可以充分利用系统的资源,提高程序的并发执行效率。

2. 数据竞争的处理在多线程并发编程中,由于多个线程共享同一份数据,可能会产生数据竞争的问题。

为了解决这个问题,我们使用互斥锁来保证数据的一致性。

在访问共享数据之前,我们使用互斥锁对数据进行加锁,防止其他线程同时对数据进行访问和修改。

3. 线程间的通信在我们的项目中,由于涉及到多个线程的协作,我们需要使用线程间的通信机制来实现任务的分配和协调。

操作系统实验报告线程并发拷贝程序定稿版

操作系统实验报告线程并发拷贝程序定稿版

操作系统实验报告线程并发拷贝程序HUA system office room 【HUA16H-TTMS2A-HUAS8Q8-HUAH1688】操作系统:线程(进程)并发拷贝程序附录一:程序代码#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<pthread.h>#include<malloc.h>#define PSIZE 4096 /*管道文件的大小*/#define BSIZE 128 /*默认缓冲区的大小*/#define NOFILE 20 /*u_ofile3575表可分配的个数*/#define NFILE 20 /*file表可分配的个数*/#define NPIPE 20 /*pipecb3575可分配的个数*//*进程的u_file表*/int u_ofile3575[NOFILE];struct{char f_flag;/*读写标志,'w'表示写,'r'表示读*/int f_count;/*表示此表项的状态,=0表示此表项没被使用,可分配;=1表示此表项在被使用,不可再分配*/int f_inode;/*对应的pipecb3575表下标*/long f_offset;/*读写指针,当前已读或已写个数*/}file[NFILE];/*管道控制块*/struct{char *p_addr;/*管道文件基地址*/int p_size;/*管道文件大小,PSIZE*/int p_count;/*=2表示读写都在被进行,=1表示在被读或被写,=0表示管道没被使用,可分配*/}pipecb3575[NPIPE];char *pfile;/*管道的写入写出端*/int fd[2];/*锁机制,实现互斥*/pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;/*进程间通信,实现同步*/pthread_cond_t rflag = PTHREAD_COND_INITIALIZER;/*读信号量*/ pthread_cond_t wflag = PTHREAD_COND_INITIALIZER;/*写信号量*/ /*线程创建函数只能传一个参数,用结构体来封装所有参数*/struct arg_set{char *fname; /*文件名*/int f; /*传递fdp[]*/};/*u_ofile3575表初始化*/int u_ofile_init3575(){printf("init the u_ofile3575\n"); int i;for(i=0;i<NOFILE;i++)u_ofile3575[i] = -1;u_ofile3575[0]=0;u_ofile3575[1]=0;u_ofile3575[2]=0;return 0;}/*创建管道*/int pipe_simulate3575(int a[]){printf("start to create a pipe\n"); int i;for(i=0;i<NOFILE;i++){if(u_ofile3575[i]==-1){a[0] = i;/*读*/u_ofile3575[i] = 0;/*读端*/ break;}}for(i;i<NOFILE;i++){if(u_ofile3575[i]==-1){a[1] = i;/*写*/u_ofile3575[i] = 1;/*写端*/ break;}if(i>=NOFILE){printf("u_ofile3575分配失败,failure to create a pipe\n");return -2;}pfile = (char *)malloc(PSIZE*sizeof(char));/*申请模拟管道用的内存空间*/ if(pfile==NULL)/*申请可能不成功*/{printf("failure to create a pipe\n");return -1;}for(i=0;i<NFILE;i++){if(file[i].f_count!=1)file[i].f_flag = 'r';/*读标志*///file[i].f_inode = 0;/*读对应pipecb3575表下标*/file[i].f_count = 1;/*file[0]这个表项在被使用,不可再分配*/ file[i].f_offset = 0;/*读指针*/u_ofile3575[a[0]] = i;/*读端*/break;}}for(i=0;i<NFILE;i++){if(file[i].f_count!=1){file[i].f_flag = 'w';/*写标志*///file[i].f_inode = 0;/*写对应pipecb3575控制块下标*/file[i].f_count = 1;/*file[1]这个表项在被使用,不可再分配*/file[i].f_offset = 0;/*写指针*/u_ofile3575[a[1]] = i;/*写端*/break;}}if(i>=NFILE){printf("failure to create a pipe\n");return -1;}for(i=0;i<NPIPE;i++){if(pipecb3575[i].p_count==0){pipecb3575[i].p_addr = pfile;/*给管道文件基地址赋值*/ pipecb3575[i].p_size = PSIZE;/*管道文件大小*/pipecb3575[i].p_count = 2;/*读写都在进行,此pipecb3575表项不可再分*/file[u_ofile3575[a[0]]].f_inode = i;file[u_ofile3575[a[1]]].f_inode = i;break;}}if(i>=NPIPE){printf("failure to create a pipe\n");return -1;}printf("Secceed create the pipe\n");return 0;/*分配成功*/}/*关闭管道*/int close_simulate3575(int a[]){printf("start to close the pipe you have created\n");char *p;int i;for(i=0;i<2;i++){p=pipecb3575[file[u_ofile3575[a[i]]].f_inode].p_addr;/*if(p!=NULL)free(p); //释放管道内存*/pipecb3575[file[u_ofile3575[a[i]]].f_inode].p_count = 0; /*管道控制块计数清零*/file[u_ofile3575[a[i]]].f_count = 0; /*file表项计数清零*/u_ofile3575[a[i]] = -1; /*u_ofile3575表项清空*/a[i] = -1; /*fdp[]清空?*/}printf("secceed close the pipe\n");return 0;}/*写管道*/int numwrite_simulate3575;int write_simulate3575(int fd,char *ca,int n)//将内存ca内容写入n个字符到管道fd里{printf("(memory---->pipe)input data in memory *ca into pipe\n");numwrite_simulate3575++;long offr,offw;/*读写指针,实际是读写字符个数*/int r;/*管道文件读端*/int m;/*若ca中的字符不能一次写完,m用来表示一次可写入的字符的最大数*/int w = u_ofile3575[fd];/*管道文件写端*/int pf = file[w].f_inode;/*读管道对应的pipecb3575表的下标*/ int n1 = n;/*一次应该写入的字符个数*/int wstart = 0;/*计数器,写入字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找写管道对应的读管道的读端*/{if((file[i].f_flag=='r')&&(file[i].f_inode==pf)){r = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if((offw+n1-PSIZE)>offr)/*不能一次写完*/{if(pipecb3575[pf].p_count==0)/*对文件的复制操作已进行结束,管道文件被释放*/{printf("对文件的复制操作已进行结束,管道文件被释放\n");return 0;}else{m = PSIZE+offr-offw;/*最多可写入数*/for(wstart=0;wstart<m;wstart++){*(pipecb3575[pf].p_addr+offw%PSIZE) = *ca;ca++;offw++;}file[w].f_offset = offw;/*重定位写指针位置*/n1 = n1-m;/*剩余需要读的字符个数*/printf("weak up the read thread , pipe is readable\n");pthread_cond_signal(&rflag);/*唤醒读线程,管道可读*/printf("write thread is blocked and under the statement of waiting\n");pthread_cond_wait(&wflag,&lock);/*写线程封锁等待*/}}/*一次性可将ca中内容全部写入管道*/offr = file[r].f_offset;offw = file[w].f_offset;for(wstart=0;wstart<n1;wstart++){/*printf("%d\n",pipecb3575[pf].p_addr);*/*(pipecb3575[pf].p_addr+offw%PSIZE) = *ca;/*printf("%d\n",wstart);*/ca++;offw++;}file[w].f_offset = offw;pthread_cond_signal(&rflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (memory---->pipe)input data in memory *ca into pipe\n"); return n;/*返回写入字符个数*/}/*读管道*/int numread_simulate3575;//read_simulate3575 diaoyongshuint read_simulate3575(int fd,char *ca,int n)//将管道fd内容读取n个字符到内存ca里{printf("(pipe---->memory)output data from pipe into memory *ca\n");numread_simulate3575++;long offr,offw;/*读写指针,实际是读写字符个数*/int w;/*管道文件写端*/int m;/*若ca中的字符不能一次读完,m用来表示一次可读出的字符的最大数*/int r = u_ofile3575[fd];/*管道文件读端*/int pf = file[r].f_inode;/*读管道对应的pipecb3575表的下标*/int rstart = 0;/*计数器,读出字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找读管道对应的读管道的端*/{if((file[i].f_flag=='w')&&(file[i].f_inode==pf)) {w = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/ offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if(offr==offw)/*管道空,无内容可读*/{printf("pipe is empty , nothing to output\n");if(pipecb3575[pf].p_count==1)/*写端关闭*/{pipecb3575[pf].p_count--;/*文件的复制以完成,释放管道文件的空间*/ printf("the write point is closed,the copy of the file is finished\n");return 0;}else{printf("weak up the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);/*唤醒写线程,管道可写*/printf("read thread is blocked and under the statement of waiting\n");pthread_cond_wait(&rflag,&lock);/*读线程封锁等待*/}}offr = file[r].f_offset;offw = file[w].f_offset;m = n<=(offw-offr)?n:(offw-offr);/*得到可读字符个数*/for(rstart=0;rstart<m;rstart++){*ca = *(pipecb3575[pf].p_addr+offr%PSIZE);ca++;offr++;}file[r].f_offset = offr;/*重定位读指针位置*/printf("weak the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (pipe---->memory)output data from the pipe into memory *ca\n");return m;}/*线程调用,读源文件,写管道*/void *pwrite3575(void *a)//将源文件a内容写入管道中{printf("(file---->pipe)input data from the original file into pipe\n"); char abuf1[BSIZE];struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/int fdr;int n_r;/*管道文件写入字符数*/if((fdr=open(args->fname,O_RDONLY))!=-1){while((n_r=read(fdr,abuf1,BSIZE))>0)/*读文件,写管道*/{printf("(file---->memory)input data in original file into memory *ca\n");printf("Secceed (file---->memory)input data in original file into memory *ca\n");//printf("(memory---->pipe)input data in memory *ca into pipe\n"); write_simulate3575(args->f,abuf1,n_r);//printf("Secceed (memory---->pipe)input\n");}pipecb3575[file[u_ofile3575[args->f]].f_inode].p_count--;/*文件已读完,关闭管道写端*/}else{perror(args->fname);/*打开源文件可能不成功*/return NULL;}printf("Secceed (file---->pipe)input data from the original file into pipe\n");return NULL;}/*线程调用,写目标文件,读管道*/void *pread3575(void *a)//读取管道,将其中内容写入新建文件中{printf("(pipe---->file)output data from the pipe into new file\n");char abuf2[BSIZE];/*缓冲区*/struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/int fdw;int n_w;/*管道文件读出字符数*/if((fdw=open(args->fname,O_CREAT|O_RDWR,0777))!=-1){while((n_w=read_simulate3575(args->f,abuf2,BSIZE))>0)/*读管道,写文件*/{//printf("(pipe---->memory)output data from pipe into memory*ca\n");//printf("Secceed (pipe---->memory)output data from pipe into memory *ca\n");printf("(memory---->file)output data in memory *ca into file\n");write(fdw,abuf2,n_w);printf("Secceed (memory---->file)output data from the pipe into new file\n");}}else{perror(args->fname);/*打开目标文件可能出错*/return NULL;}printf("Secceed (pipe---->file)output data from the pipe into new file\n"); return NULL;}/*主函数*/int main(int argc,char *argv[]){int x;u_ofile_init3575();while((x=pipe_simulate3575(fd))==-1);/*创建管道,即申请空间*/if(x==-2)return -1;pthread_t t;//thread IDstruct arg_set args[2];/*用结构体传写线程需要的参数:文件名,管道文件读写端*/args[0].fname=argv[1];/*源文件名*/args[0].f=fd[1];/*管道文件写端*/args[1].fname=argv[2];/*目标文件名*/args[1].f=fd[0];/*管道文件读端*/pthread_create(&t,NULL,pwrite3575,(void *)&args[0]);/*创建子线程,写管道*/ pread3575((void *)&args[1]);/*主线程调用,读管道*/pthread_join(t,NULL);/*等待写线程结束*/close_simulate3575(fd);printf("\nnum of read_simulate3575 = %d\n",numread_simulate3575); printf("num of write_simulate3575 = %d\n",numwrite_simulate3575); return 0;}附录二(实验结果):ls -l总用量 2379-rw-r--r-- 1 john john 50 2012-12-17 18:06 3575-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3575.doc-rw-r--r-- 1 john john 95441 2012-08-27 22:16 3575.JPG-rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3575.mp3-rw-r--r-- 1 john john 84835 2012-07-11 13:22 3575.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3575.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3575.rar-rw-r--r-- 1 john john 0 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cpp ./tc 3575 a3575 > copy1./tc 3575 a3575.doc./tc 3575.doc a3575.doc./tc 3575.ppt a3575.ppt./tc 3575.mp3 a3575.mp3./tc 3575.rar a3575.rar > copy2./tc 3575.pdf a3575.rarls -l总用量 5163-rw-r--r-- 1 john john 50 2012-12-17 18:06 3575-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3575.doc-rw-r--r-- 1 john john 95441 2012-08-27 22:16 3575.JPG-rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3575.mp3-rw-r--r-- 1 john john 84835 2012-07-11 13:22 3575.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3575.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3575.rar-rwxr-xr-x 1 john john 50 2012-12-17 22:51 a3575-rwxr-xr-x 1 john john 36864 2012-12-17 22:51 a3575.doc -rwxr-xr-x 1 john john 95441 2012-12-17 22:53 a3575.JPG -rwxr-xr-x 1 john john 2083969 2012-12-17 22:54 a3575.mp3 -rwxr-xr-x 1 john john 84835 2012-12-17 22:56 a3575.pdf -rwxr-xr-x 1 john john 73728 2012-12-17 22:53 a3575.ppt -rwxr-xr-x 1 john john 19924 2012-12-17 22:55 a3575.rar -rw-r--r-- 1 john john 1320 2012-12-17 22:51 copy1-rw-r--r-- 1 john john 419294 2012-12-17 22:56 copy2-rw-r--r-- 1 john john 690 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 0 2012-12-17 22:57 sta2-rwxr-xr-x 1 john john 12256 2012-12-17 22:50 tc-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cpp cat copy1init the u_ofilestart to create a pipeSecceed create the pipe(pipe---->file)output data from the pipe into new file(pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputweak up the write thread , make the pipe writableread thread is blocked and under the statement of waiting(file---->pipe)input data from the original file into pipe(file---->memory)input data in original file into memory *ca Secceed (file---->memory)input data in original file into memory *ca (memory---->pipe)input data in memory *ca into pipe----add the lock----release the lockSecceed (memory---->pipe)input data in memory *ca into pipeSecceed (file---->pipe)input data from the original file into pipe weak the write thread , make the pipe writable----release the lockSecceed (pipe---->memory)output data from the pipe into memory *ca (memory---->file)output data in memory *ca into fileSecceed (memory---->file)output data from the pipe into new file (pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputthe write point is closed,the copy of the file is finished Secceed (pipe---->file)output data from the pipe into new file start to close the pipe you have createdsecceed close the pipenum of readp = 2num of writep = 1。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

操作系统:线程(进程)并发拷贝程序附录一:程序代码#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>#include<pthread.h>#include<malloc.h>#define PSIZE 4096 /*管道文件的大小*/#define BSIZE 128 /*默认缓冲区的大小*/#define NOFILE 20 /*u_ofile3705表可分配的个数*/#define NFILE 20 /*file表可分配的个数*/#define NPIPE 20 /*pipecb3705可分配的个数*//*进程的u_file表*/int u_ofile3705[NOFILE];/*模拟file表*/struct{char f_flag;/*读写标志,'w'表示写,'r'表示读*/int f_count;/*表示此表项的状态,=0表示此表项没被使用,可分配;=1表示此表项在被使用,不可再分配*/int f_inode;/*对应的pipecb3705表下标*/long f_offset;/*读写指针,当前已读或已写个数*/}file[NFILE];/*管道控制块*/struct{char *p_addr;/*管道文件基地址*/int p_size;/*管道文件大小,PSIZE*/int p_count;/*=2表示读写都在被进行,=1表示在被读或被写,=0表示管道没被使用,可分配*/}pipecb3705[NPIPE];/*模拟管道文件*/char *pfile;/*管道的写入写出端*/int fd[2];/*锁机制,实现互斥*/pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;/*进程间通信,实现同步*/pthread_cond_t rflag = PTHREAD_COND_INITIALIZER;/*读信号量*/pthread_cond_t wflag = PTHREAD_COND_INITIALIZER;/*写信号量*//*线程创建函数只能传一个参数,用结构体来封装所有参数*/struct arg_set{char *fname; /*文件名*/int f; /*传递fdp[]*/};/*u_ofile3705表初始化*/int u_ofile_init3705(){printf("init the u_ofile3705\n");int i;for(i=0;i<NOFILE;i++)u_ofile3705[i] = -1;u_ofile3705[0]=0;u_ofile3705[1]=0;u_ofile3705[2]=0;return 0;}/*创建管道*/int pipe_simulate3705(int a[]){printf("start to create a pipe\n");int i;for(i=0;i<NOFILE;i++){if(u_ofile3705[i]==-1){a[0] = i;/*读*/u_ofile3705[i] = 0;/*读端*/break;}}for(i;i<NOFILE;i++){if(u_ofile3705[i]==-1){a[1] = i;/*写*/u_ofile3705[i] = 1;/*写端*/break;}}if(i>=NOFILE){printf("u_ofile3705分配失败,failure to create a pipe\n");return -2;}pfile = (char *)malloc(PSIZE*sizeof(char));/*申请模拟管道用的内存空间*/if(pfile==NULL)/*申请可能不成功*/{printf("failure to create a pipe\n");return -1;}for(i=0;i<NFILE;i++){if(file[i].f_count!=1){file[i].f_flag = 'r';/*读标志*///file[i].f_inode = 0;/*读对应pipecb3705表下标*/file[i].f_count = 1;/*file[0]这个表项在被使用,不可再分配*/file[i].f_offset = 0;/*读指针*/u_ofile3705[a[0]] = i;/*读端*/break;}}for(i=0;i<NFILE;i++){if(file[i].f_count!=1){file[i].f_flag = 'w';/*写标志*///file[i].f_inode = 0;/*写对应pipecb3705控制块下标*/file[i].f_count = 1;/*file[1]这个表项在被使用,不可再分配*/file[i].f_offset = 0;/*写指针*/u_ofile3705[a[1]] = i;/*写端*/break;}}if(i>=NFILE){printf("failure to create a pipe\n");return -1;}for(i=0;i<NPIPE;i++){if(pipecb3705[i].p_count==0){pipecb3705[i].p_addr = pfile;/*给管道文件基地址赋值*/pipecb3705[i].p_size = PSIZE;/*管道文件大小*/pipecb3705[i].p_count = 2;/*读写都在进行,此pipecb3705表项不可再分*/file[u_ofile3705[a[0]]].f_inode = i;file[u_ofile3705[a[1]]].f_inode = i;break;}}if(i>=NPIPE){printf("failure to create a pipe\n");return -1;}printf("Secceed create the pipe\n");return 0;/*分配成功*/}/*关闭管道*/int close_simulate3705(int a[]){printf("start to close the pipe you have created\n");char *p;int i;for(i=0;i<2;i++){p=pipecb3705[file[u_ofile3705[a[i]]].f_inode].p_addr;/*if(p!=NULL)free(p); //释放管道内存*/pipecb3705[file[u_ofile3705[a[i]]].f_inode].p_count = 0; /*管道控制块计数清零*/file[u_ofile3705[a[i]]].f_count = 0; /*file表项计数清零*/u_ofile3705[a[i]] = -1; /*u_ofile3705表项清空*/a[i] = -1; /*fdp[]清空?*/}printf("secceed close the pipe\n");return 0;}/*写管道*/int numwrite_simulate3705;int write_simulate3705(int fd,char *ca,int n)//将内存ca内容写入n个字符到管道fd里{printf("(memory---->pipe)input data in memory *ca into pipe\n");numwrite_simulate3705++;long offr,offw;/*读写指针,实际是读写字符个数*/int r;/*管道文件读端*/int m;/*若ca中的字符不能一次写完,m用来表示一次可写入的字符的最大数*/int w = u_ofile3705[fd];/*管道文件写端*/int pf = file[w].f_inode;/*读管道对应的pipecb3705表的下标*/int n1 = n;/*一次应该写入的字符个数*/int wstart = 0;/*计数器,写入字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找写管道对应的读管道的读端*/{if((file[i].f_flag=='r')&&(file[i].f_inode==pf)){r = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if((offw+n1-PSIZE)>offr)/*不能一次写完*/{if(pipecb3705[pf].p_count==0)/*对文件的复制操作已进行结束,管道文件被释放*/{printf("对文件的复制操作已进行结束,管道文件被释放\n");return 0;}else{m = PSIZE+offr-offw;/*最多可写入数*/for(wstart=0;wstart<m;wstart++){*(pipecb3705[pf].p_addr+offw%PSIZE) = *ca;ca++;offw++;}file[w].f_offset = offw;/*重定位写指针位置*/n1 = n1-m;/*剩余需要读的字符个数*/printf("weak up the read thread , pipe is readable\n");pthread_cond_signal(&rflag);/*唤醒读线程,管道可读*/printf("write thread is blocked and under the statement of waiting\n");pthread_cond_wait(&wflag,&lock);/*写线程封锁等待*/}}/*一次性可将ca中内容全部写入管道*/offr = file[r].f_offset;offw = file[w].f_offset;for(wstart=0;wstart<n1;wstart++){/*printf("%d\n",pipecb3705[pf].p_addr);*/*(pipecb3705[pf].p_addr+offw%PSIZE) = *ca;/*printf("%d\n",wstart);*/ca++;offw++;}file[w].f_offset = offw;pthread_cond_signal(&rflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (memory---->pipe)input data in memory *ca into pipe\n");return n;/*返回写入字符个数*/}/*读管道*/int numread_simulate3705;//read_simulate3705 diaoyongshuint read_simulate3705(int fd,char *ca,int n)//将管道fd内容读取n个字符到内存ca 里{printf("(pipe---->memory)output data from pipe into memory *ca\n");numread_simulate3705++;long offr,offw;/*读写指针,实际是读写字符个数*/int w;/*管道文件写端*/int m;/*若ca中的字符不能一次读完,m用来表示一次可读出的字符的最大数*/int r = u_ofile3705[fd];/*管道文件读端*/int pf = file[r].f_inode;/*读管道对应的pipecb3705表的下标*/int rstart = 0;/*计数器,读出字符个数*/int i = 0;for(i;i<NFILE;i++)/*寻找读管道对应的读管道的端*/{if((file[i].f_flag=='w')&&(file[i].f_inode==pf)){w = i;break;}else{continue;}}printf("----add the lock\n");pthread_mutex_lock(&lock);/*互斥锁,相当于进入临界区*/offr = file[r].f_offset;/*赋值读指针*/offw = file[w].f_offset;/*赋值写指针*/if(offr==offw)/*管道空,无内容可读*/{printf("pipe is empty , nothing to output\n");if(pipecb3705[pf].p_count==1)/*写端关闭*/{pipecb3705[pf].p_count--;/*文件的复制以完成,释放管道文件的空间*/ printf("the write point is closed,the copy of the file is finished\n"); return 0;}else{printf("weak up the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);/*唤醒写线程,管道可写*/printf("read thread is blocked and under the statement of waiting\n"); pthread_cond_wait(&rflag,&lock);/*读线程封锁等待*/}}offr = file[r].f_offset;offw = file[w].f_offset;m = n<=(offw-offr)?n:(offw-offr);/*得到可读字符个数*/for(rstart=0;rstart<m;rstart++){*ca = *(pipecb3705[pf].p_addr+offr%PSIZE);ca++;offr++;}file[r].f_offset = offr;/*重定位读指针位置*/printf("weak the write thread , make the pipe writable\n");pthread_cond_signal(&wflag);printf("----release the lock\n");pthread_mutex_unlock(&lock);printf("Secceed (pipe---->memory)output data from the pipe into memory *ca\n"); return m;}/*线程调用,读源文件,写管道*/void *pwrite3705(void *a)//将源文件a内容写入管道中{printf("(file---->pipe)input data from the original file into pipe\n");char abuf1[BSIZE];struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/ int fdr;int n_r;/*管道文件写入字符数*/if((fdr=open(args->fname,O_RDONLY))!=-1){while((n_r=read(fdr,abuf1,BSIZE))>0)/*读文件,写管道*/{printf("(file---->memory)input data in original file into memory *ca\n");printf("Secceed (file---->memory)input data in original file into memory *ca\n");//printf("(memory---->pipe)input data in memory *ca into pipe\n"); write_simulate3705(args->f,abuf1,n_r);//printf("Secceed (memory---->pipe)input\n");}pipecb3705[file[u_ofile3705[args->f]].f_inode].p_count--;/*文件已读完,关闭管道写端*/}else{perror(args->fname);/*打开源文件可能不成功*/return NULL;}printf("Secceed (file---->pipe)input data from the original file into pipe\n"); return NULL;}/*线程调用,写目标文件,读管道*/void *pread3705(void *a)//读取管道,将其中内容写入新建文件中{printf("(pipe---->file)output data from the pipe into new file\n");char abuf2[BSIZE];/*缓冲区*/struct arg_set *args=(struct arg_set *)a;/*需要传入多个参数时,用结构体传*/ int fdw;int n_w;/*管道文件读出字符数*/if((fdw=open(args->fname,O_CREAT|O_RDWR,0777))!=-1){while((n_w=read_simulate3705(args->f,abuf2,BSIZE))>0)/*读管道,写文件*/ {//printf("(pipe---->memory)output data from pipe into memory *ca\n"); //printf("Secceed (pipe---->memory)output data from pipe into memory *ca\n");printf("(memory---->file)output data in memory *ca into file\n");write(fdw,abuf2,n_w);printf("Secceed (memory---->file)output data from the pipe into new file\n");}}else{perror(args->fname);/*打开目标文件可能出错*/return NULL;}printf("Secceed (pipe---->file)output data from the pipe into new file\n"); return NULL;}/*主函数*/int main(int argc,char *argv[]){int x;u_ofile_init3705();while((x=pipe_simulate3705(fd))==-1);/*创建管道,即申请空间*/if(x==-2)return -1;pthread_t t;//thread IDstruct arg_set args[2];/*用结构体传写线程需要的参数:文件名,管道文件读写端*/ args[0].fname=argv[1];/*源文件名*/args[0].f=fd[1];/*管道文件写端*/args[1].fname=argv[2];/*目标文件名*/args[1].f=fd[0];/*管道文件读端*/pthread_create(&t,NULL,pwrite3705,(void *)&args[0]);/*创建子线程,写管道*/pread3705((void *)&args[1]);/*主线程调用,读管道*/pthread_join(t,NULL);/*等待写线程结束*/close_simulate3705(fd);printf("\nnum of read_simulate3705 = %d\n",numread_simulate3705);printf("num of write_simulate3705 = %d\n",numwrite_simulate3705);return 0;}附录二(实验结果):ls -l总用量 2379-rw-r--r-- 1 john john 50 2012-12-17 18:06 3705-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3705.doc-rw-r--r-- 1 john john 95441 2012-08-27 22:16 3705.JPG-rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3705.mp3-rw-r--r-- 1 john john 84835 2012-07-11 13:22 3705.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3705.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3705.rar-rw-r--r-- 1 john john 0 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cpp./tc 3705 a3705 > copy1./tc 3705 a3705.doc./tc 3705.doc a3705.doc./tc 3705.ppt a3705.ppt./tc 3705.mp3 a3705.mp3./tc 3705.rar a3705.rar > copy2./tc 3705.pdf a3705.rarls -l总用量 5163-rw-r--r-- 1 john john 50 2012-12-17 18:06 3705-rw-r--r-- 1 john john 36864 2012-07-15 07:53 3705.doc-rw-r--r-- 1 john john 95441 2012-08-27 22:16 3705.JPG-rw-r--r-- 1 john john 2083969 2010-11-08 13:07 3705.mp3-rw-r--r-- 1 john john 84835 2012-07-11 13:22 3705.pdf-rw-r--r-- 1 john john 73728 2012-12-17 16:48 3705.ppt-rw-r--r-- 1 john john 19924 2012-07-03 18:51 3705.rar-rwxr-xr-x 1 john john 50 2012-12-17 22:51 a3705-rwxr-xr-x 1 john john 36864 2012-12-17 22:51 a3705.doc -rwxr-xr-x 1 john john 95441 2012-12-17 22:53 a3705.JPG -rwxr-xr-x 1 john john 2083969 2012-12-17 22:54 a3705.mp3 -rwxr-xr-x 1 john john 84835 2012-12-17 22:56 a3705.pdf -rwxr-xr-x 1 john john 73728 2012-12-17 22:53 a3705.ppt -rwxr-xr-x 1 john john 19924 2012-12-17 22:55 a3705.rar -rw-r--r-- 1 john john 1320 2012-12-17 22:51 copy1-rw-r--r-- 1 john john 419294 2012-12-17 22:56 copy2-rw-r--r-- 1 john john 690 2012-12-17 22:49 sta1-rw-r--r-- 1 john john 0 2012-12-17 22:57 sta2-rwxr-xr-x 1 john john 12256 2012-12-17 22:50 tc-rw-r--r-- 1 john john 11563 2012-12-17 22:46 tc_copy.cppcat copy1init the u_ofilestart to create a pipeSecceed create the pipe(pipe---->file)output data from the pipe into new file(pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputweak up the write thread , make the pipe writableread thread is blocked and under the statement of waiting(file---->pipe)input data from the original file into pipe(file---->memory)input data in original file into memory *ca Secceed (file---->memory)input data in original file into memory *ca (memory---->pipe)input data in memory *ca into pipe----add the lock----release the lockSecceed (memory---->pipe)input data in memory *ca into pipeSecceed (file---->pipe)input data from the original file into pipe weak the write thread , make the pipe writable----release the lockSecceed (pipe---->memory)output data from the pipe into memory *ca (memory---->file)output data in memory *ca into fileSecceed (memory---->file)output data from the pipe into new file (pipe---->memory)output data from pipe into memory *ca----add the lockpipe is empty , nothing to outputthe write point is closed,the copy of the file is finishedSecceed (pipe---->file)output data from the pipe into new filestart to close the pipe you have createdsecceed close the pipenum of readp = 2num of writep = 1。

相关文档
最新文档