您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 经营企划 > 山东大学操作系统实验二
软件学院操作系统实验报告实验题目:实验二、线程和进程/线程管道通信实验学号:201100300124日期:2013年04月19日班级:5班姓名:韩俊晓Email:hanjunxiao188@gmail.com实验目的:通过Linux系统中线程和管道通信机制的实验,加深对于线程控制和管道通信概念的理解,观察和体验并发进/线程间的通信和协作的效果,练习利用无名管道进行进/线程间通信的编程和调试技术。实验要求:设有二元函数f(x,y)=f(x)+f(y)其中:f(x)=f(x-1)*x(x1)f(x)=1(x=1)f(y)=f(y-1)+f(y-2)(y2)f(y)=1(y=1,2)请编程建立3个并发协作进程(或线程),它们分别完成f(x,y)、f(x)、f(y)其中由父进程(或主线程)完成:f(x,y)=f(x)+f(y)由子进程1(或线程1)完成:f(x)=f(x-1)*x(x1)f(x)=1(x=1)由子进程2(或线程2)完成:f(y)=f(y-1)+f(y-2)(y2)f(y)=1(y=1,2)硬件环境:实验室计算机软件环境:Ubuntu08.4-Linux操作系统BASH_VERSION='3.2.33(1)-releasegccversion4.1.2gedit2.18.2OpenOffice2.3实验步骤:1.实验说明:1)与线程创建、执行有关的系统调用说明线程是在共享内存中并发执行的多道执行路径,它们共享一个进程的资源,如进程程序段、文件描述符和信号等,但有各自的执行路径和堆栈。线程的创建无需像进程那样重新申请系统资源,线程在上下文切换时也无需像进程那样更换内存映像。多线程的并发执行即避免了多进程并发的上下文切换的开销又可以提高并发处理的效率。Linux利用了特有的内核函数__clone实现了一个叫phread的线程库,__clone是fork函数的替代函数,通过更多的控制父子进程共享哪些资源而实现了线程。Pthread是一个标准化模型,用它可把一个程序分成一组能够并发执行的多个任务。phread线程库是POSIX线程标准的实现,它提供了C函数的线程调用接口和数据结构。线程可能的应用场合包括:在返回前阻塞的I/O任务能够使用一个线程处理I/O,同时继续执行其他处理。需要及时响应多个前台用户界面操作同时后台处理的多任务场合。在一个或多个任务受不确定事件影响时能够处理异步事件同时继续进行正常处理。如果某些程序功能比其他功能更重要,可以使用线程以保证所有功能都出现,但那些时间密集型的功能具有更高优先级。2)下面介绍pthread库中最基本的调用。pthread_create系统调用语法:#includepthread.hIntpthread_create(pthread_t*thread,pthread_attr_t*attr,void*(*start_routine)(void*)Void*arg);pthread_create函数创建一个新的线程。pthread_create在thread中保存新线程的标识符。Attr决定了线程应用那种线程属性。使用默认可给定参数NULL;(*start_routine)是一个指向新线程中要执行的函数的指针arg是新线程函数携带的参数。Pthread_create执行成功会返回0并在thread中保存线程标识符。执行失败则返回一个非0的出错代码。pthread_exit系统调用语法:#includepthread.hvoidpthread_exit(void*retval);pthread_exit函数使用函数pthread_cleanup_push调用任何用于该线程的清除处理函数,然后中止当前进程的执行,返回retval。Retval可以由父线程或其他线程通过pthread_join来检索。一个线程也可以简单地通过从其初始化函数返回来终止。pthread_join系统调用语法:#includepthread.hintpthread_join(pthread_tth,void**thread_return);intpthread_detach(pthread_tth);函数pthread_join用于挂起当前线程,直到th指定的线程终止运行为止。另一个线程的返回值如果不为NULL,则保存在thread_return指向的地址中。一个线程所使用的内存资源在对该线程应用pthread_join调用之前不会被重新分配。因而对于每个可切入的线程(默认的)必须调用一次pthread_join函数。线程必须是可切入的而不是被分离的状态,并且其他线程不能对同一线程再应用pthread_join调用。通过在pthread_create调用创建一个线程时使用PTHREAD_CREATE_DETACHED属性或者使用pthread_detach可以让线程处于被分离状态。注意不像由fork创建的进程可以使用众多wait等待子进程退出,在pthread多线程中似乎没有等待某个线程退出的方法。3)管道通信机制管道pipe是进程间通信最基本的一种机制。在内存中建立的管道称为无名管道,在磁盘上建立的管道称为有名管道。无名管道随着进程的撤消而消失,有名管道则可以长久保存,shell命令符|建立的就是无名管道,而shell命令mkfifo建立的是有名管道。两个进程可以通过管道一个在管道一端向管道发送其输出,给另一进程可以在管道的另一端从管道得到其输入.管道以半双工方式工作,即它的数据流是单方向的.因此使用一个管道一般的规则是读管道数据的进程关闭管道写入端,而写管道进程关闭其读出端。管道既可以采用同步方式工作也可以采用异步方式工作。pipe系统调用的语法为:#includeunistd.hintpipe(intpipe_id[2]);pipe建立一个无名管道,pipe_id[0]中和pipe_id[1]将放入管道两端的描述符如果pipe执行成功返回0。.出错返回-1.管道读写的系统调用语法为:#includeunistd.hssize_tread(intpipe_id,constvoid*buf,size_tcount);ssize_twrite(intpipe_id,constvoid*buf,size_tcount);read和write分别在管道的两端进行读和写。pipe_id是pipe系统调用返回的管道描述符。Buf是数据缓冲区首地址,count说明数据缓冲区以size_t为单位的长度。read和write的返回值为它们实际读写的数据单位。注意管道的读写默认的通信方式为同步读写方式,即如果管道读端无数据则读者阻塞直到数据到达,反之如果管道写端有数据则写者阻塞直到数据被读走。2.实验代码设计说明:一个父进程创建两个子进程,这两个子进程分别执行X的计算和Y的计算,然后将计算结果写回到自己的管道中,再由父进程读取子进程的管道,将数据读到父进程的管道中,从而得到最后的结果。3.调试过程:1)建立experiment2.c程序,将代码写到程序中;2)建立以下项目管理文件Makefilesrcs=experiment2.cobjs=experiment2.oopts=-g-call:experiment2experiment2:$(objs)gcc$(objs)-oexperiment2experiment2.o:$(srcs)gcc$(opts)$(srcs)clean:rmexperiment2*.o3)输入make命令编译连接生成可执行的experiment2程序$gmakegcc-g-cexperiment2.cgccexperiment2.o-oexperiment24)执行experiment2程序实验总结:1.编写递归函数的时候要看明白控制条件,不要遗漏控制条件从而使函数出错。2.编写程序时要理清管道之间的读写关系,这样才不会在读写的过程中出错。3.程序的错误可以通过打印到屏幕来调试,这也是一种要掌握的调试技能。
本文标题:山东大学操作系统实验二
链接地址:https://www.777doc.com/doc-5188731 .html