实验一一进程创建实验.docx

上传人:b****4 文档编号:6619928 上传时间:2023-05-10 格式:DOCX 页数:11 大小:23.13KB
下载 相关 举报
实验一一进程创建实验.docx_第1页
第1页 / 共11页
实验一一进程创建实验.docx_第2页
第2页 / 共11页
实验一一进程创建实验.docx_第3页
第3页 / 共11页
实验一一进程创建实验.docx_第4页
第4页 / 共11页
实验一一进程创建实验.docx_第5页
第5页 / 共11页
实验一一进程创建实验.docx_第6页
第6页 / 共11页
实验一一进程创建实验.docx_第7页
第7页 / 共11页
实验一一进程创建实验.docx_第8页
第8页 / 共11页
实验一一进程创建实验.docx_第9页
第9页 / 共11页
实验一一进程创建实验.docx_第10页
第10页 / 共11页
实验一一进程创建实验.docx_第11页
第11页 / 共11页
亲,该文档总共11页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

实验一一进程创建实验.docx

《实验一一进程创建实验.docx》由会员分享,可在线阅读,更多相关《实验一一进程创建实验.docx(11页珍藏版)》请在冰点文库上搜索。

实验一一进程创建实验.docx

实验一一进程创建实验

实验一一进程创建实验

实验一

(一)进程的创建实验实验目的1、掌握进程的概念,明确进程的含义2、认识并了解并发执行的实质实验内容1、编写一段程序,使用系统调用fork()创建两个子进程。

当此程序运行时,在系统中有一个父进程和两个子进程活动。

让每一个进程在屏幕上显示一个字符:

父进程显示"a",子进程分别显示字符"b"和字符"c"。

试观察记录屏幕上的显示结果,并分析原因。

2、修改上述程序,每一个进程循环显示一句话。

子进程显示"daughter"及"son",父进程显示"parent",观察结果,分析原因。

实验准备

(1)阅读LINUX的fork.c源码文件(见附录二),分析进程的创建过程。

(2)阅读LINUX的sched.c源码文件(见附录三),加深对进程管理概念的认识。

实验指导一、进程UNIX中,进程既是一个独立拥有资源的基本单位,又是一个独立调度的基本单位。

一个进程实体由若干个区(段)组成,包括程序区、数据区、栈区、共享存储区等。

每个区又分为若干页,每个进程配置有唯一的进程控制块PCB,用于控制和管理进程。

PCB的数据结构如下:

1、进程表项(ProcessTableEntry)。

包括一些最常用的核心数据:

进程标识符PID、用户标识符UID、进程状态、事件描述符、进程和U区在内存或外存的地址、软中断信号、计时域、进程的大小、偏置值nice、指向就绪队列中下一个PCB的指针P_Link、指向U区进程正文、数据及栈在内存区域的指针。

2、U区(UArea)。

用于存放进程表项的一些扩充信息。

每一个进程都有一个私用的U区,其中含有:

进程表项指针、真正用户标识符u-ruid(readuserID)、有效用户标识符u-euid(effectiveuserID)、用户文件描述符表、计时器、内部I/O参数、限制字段、差错字段、返回值、信号处理数组。

由于UNIX系统采用段页式存储管理,为了把段的起始虚地址变换为段在系统中的物理地址,便于实现区的共享,所以还有:

3、系统区表项。

以存放各个段在物理存储器中的位置等信息。

系统把一个进程的虚地址空间划分为若干个连续的逻辑区,有正文区、数据区、栈区等。

这些区是可被共享和保护的独立实体,多个进程可共享一个区。

为了对区进行管理,核心中设置一个系统区表,各表项中记录了以下有关描述活动

区的信息:

区的类型和大小、区的状态、区在物理存储器中的位置、引用计数、指向文件索引结点的指针。

4、进程区表系统为每个进程配置了一张进程区表。

表中,每一项记录一个区的起始虚地址及指向系统区表中对应的区表项。

核心通过查找进程区表和系统区表,便可将区的逻辑地址变换为物理地址。

二、进程映像UNIX系统中,进程是进程映像的执行过程,也就是正在执行的进程实体。

它由三部分组成:

1、用户级上、下文。

主要成分是用户程序;2、寄存器上、下文。

由CPU中的一些寄存器的内容组成,如PC,PSW,SP及通用寄存器等;3、系统级上、下文。

包括OS为管理进程所用的信息,有静态和动态之分。

三、所涉及的系统调用1、fork()创建一个新进程。

系统调用格式:

pid=fork()参数定义:

intfork()fork()返回值意义如下:

0:

在子进程中,pid变量保存的fork()返回值为0,表示当前进程是子进程。

0:

在父进程中,pid变量保存的fork()返回值为子进程的id值(进程唯一标识符)。

-1:

创建失败。

如果fork()调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork()被调用了一次,但返回了两次。

此时OS在内存中建立一个新进程,所建的新进程是调用fork()父进程(parentprocess)的副本,称为子进程(childprocess)。

子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。

父进程与子进程并发执行。

核心为fork()完成以下操作:

(1)为新进程分配一进程表项和进程标识符进入fork()后,核心检查系统是否有足够的资源来建立一个新进程。

若资源不足,则fork()系统调用失败;否则,核心为新进程分配一进程表项和唯一的进程标识符。

(2)检查同时运行的进程数目超过预先规定的最大数目时,fork()系统调用失败。

(3)拷贝进程表项中的数据将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为创建状态。

(4)子进程继承父进程的所有文件对父进程当前目录和所有已打开的文件表项中的引用计数加1。

(5)为子进程创建进程上、下文

PC进程创建结束,设子进程状态为内存中就绪并返回子进程的标识符。

(6)子进程执行虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork()返回值的不同,执行了不同的分支语句。

例:

fork()调用前fork()调用后实验二二进程管理进程互斥实验实验目的1、进一步认识并发执行的实质2、分析进程竞争资源的现象,学习解决进程互斥的方法实验内容1、修改实验

(一)中的程序,用lockf()来给每一个进程加锁,以实现进程之间的互斥2、观察并分析出现的现象实验指导..pid=fork();if(!

pid)printf(I"mthechildprocess!

\nelseif(pid0)printf(I"mtheparentprocess!

\nelseprintf(Forkfail!

\n..pid=fork();if(!

pid)printf(I"mthechildprocess!

\nelseif(pid0)printf(I"mtheparentprocess!

\nelseprintf(Forkfail!

\n..pid=fork();if(!

pid)printf(I"mthechildprocess!

\nelseif(pid0)printf(I"mtheparentprocess!

\nelseprintf(Forkfail!

\nPCPC

一、所涉及的系统调用lockf(files,function,size)用作锁定文件的某些段或者整个文件。

本函数的头文件为#includeunistd.h参数定义:

intlockf(files,function,size)intfiles,function;longsize;其中:

files是文件描述符;function是锁定和解锁:

1表示锁定,0表示解锁。

size是锁定或解锁的字节数,为0,表示从文件的当前位置到文件尾。

三、运行结果四、分析原因上述程序执行时,不同进程之间不存在共享临界资源(其中打印机的互斥性已由操作系统保证)问题,所以加锁与不加锁效果相同。

五、分析以下程序的输出结果:

#includestdio.h#includeunistd.hmain(){intp1,p2,i;int*fp;fp=fopen(to_be_,w+if(fp==NULL){printf(Failtocreatefileexit(-1);}while((p1=fork())==-1);/*创建子进程p1*/if(p1==0){lockf(*fp,1,0);/*加锁*/for(i=0;ii++)fprintf(fp,daughter%d\n,i);lockf(*fp,0,0);/*解锁*/}else{while((p2=fork())==-1);/*创建子进程p2*/if(p2==0){lockf(*fp,1,0);/*加锁*/for(i=0;ii++)fprintf(fp,son%d\n,i);

lockf(*fp,0,0);/*解锁*/}else{wait(NULL);lockf(*fp,1,0);/*加锁*/for(i=0;ii++)fprintf(fp,parent%d\n,i);lockf(*fp,0,0);/*解锁*/}}fclose(fp);}catto_be_查看输出结果实验二进程间通信UNIX/LINUX系统的进程间通信机构(IPC)允许在任意进程间大批量地交换数据。

本实验的目的是了解和熟悉LINUX支持的信号量机制、管道机制、消息通信机制及共享存储区机制。

(一)信号机制实验实验目的

1、了解什么是信号2、熟悉LINUX系统中进程之间软中断通信的基本原理实验内容1、编写程序:

用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:

Childprocess1iskilledbyparent!

Childprocess2iskilledbyparent!

父进程等待两个子进程终止后,输出如下的信息后终止:

Parentprocessiskilled!

2、分析利用软中断通信实现进程同步的机理实验指导一、信号1、信号的基本概念每个信号都对应一个正整数常量(称为signalnumber,即信号编号。

定义在系统头文件signal.h中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。

每个进程在运行时,都要通过信号机制来检查是否有信号到达。

若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。

实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断。

信号与中断的相似点:

(1)采用了相同的异步通信方式;

(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;(3)都在处理完毕后返回到原来的断点;(4)对信号或中断都可进行屏蔽。

信号与中断的区别:

(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;

(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;(3)中断响应是及时的,而信号响应通常都有较大的时间延迟。

信号机制具有以下三方面的功能:

(1)发送信号。

发送信号的程序用系统调用kill()实现;

(2)预置对信号的处理方式。

接收信号的程序用signal()来实现对处理方式的预置;(3)收受信号的进程按事先的规定完成对相应事件的处理。

2、信号的发送信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上。

如果目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此结束。

一个进程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个。

进程用kill()向一个进程或一组进程发送一个信号。

3、对信号的处理当一个进程要进入或退出一个低优先级睡眠状态时,或一个进程即将从核心态返回用户态时,核心都要检查该进程是否已收到软中断。

当进程处于核心态时,即使收到软中断也不予理睬;只有当它返回到用户态后,才处理软中断信号。

对软中断信号的处理分三种情况进行:

(1)如果进程收到的软中断是一个已决定要忽略的信号(function=1),进程不做任何处理便立即返回;

(2)进程收到软中断后便退出(function=0);(3)执行用户设置的软中断处理程序。

二、所涉及的中断调用1、kill()系统调用格式intkill(pid,sig)参数定义intpid,sig;其中,pid是一个或一组进程的标识符,参数sig是要发送的软中断信号。

(1)pid0时,核心将信号发送给进程pid。

(2)pid=0时,核心将信号发送给与发送进程同组的所有进程。

(3)pid=-1时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。

2、signal()预置对信号的处理方式,允许调用进程控制软中断信号。

系统调用格式signal(sig,function)头文件为#includesignal.h参数定义signal(sig,function)intsig;void(*func)()其中sig用于指定信号的类型,sig为0则表示没有收到任何信号,余者如下表:

值名字说明01SIGHUP挂起(hangup)02SIGINT中断,当用户从键盘按^c键或^break键时03SIGQUIT退出,当用户从键盘按quit键时04SIGILL非法指令05SIGTRAP跟踪陷阱(tracetrap),启动进程,跟踪代码的执行06SIGIOTIOT指令07SIGEMTEMT指令08SIGFPE浮点运算溢出09SIGKILL杀死、终止进程10SIGBUS总线错误11SIGSEGV段违例(segmentationviolation),进程试图去访问其虚地址空间

以外的位置12SIGSYS系统调用中参数错,如系统调用号非法13SIGPIPE向某个非读管道中写入数据14SIGALRM闹钟。

当某进程希望在某时间后接收信号时发此信号15SIGTERM软件终止(softwaretermination)16SIGUSR1用户自定义信号117SIGUSR2用户自定义信号218SIGCLD某个子进程死19SIGPWR电源故障function:

在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号SIGKILL,SIGTRAP和SIGPWR以外的信号,核心自动地重新设置软中断信号处理程序的值为SIG_DFL,一个进程不能捕获SIGKILL信号。

function的解释如下:

(1)function=1时,进程对sig类信号不予理睬,亦即屏蔽了该类信号;

(2)function=0时,缺省值,进程在收到sig信号后应终止自己;(3)function为非0,非1类整数时,function的值即作为信号处理程序的指针。

四、运行结果五、分析原因六、思考1、该程序段前面部分用了两个wait(0),它们起什么作用?

2、该程序段中每个进程退出时都用了语句exit(0),为什么?

3、为何预期的结果并未显示出?

4、程序该如何修改才能得到正确结果?

5、不修改程序如何得到期望的输出?

实验三进程通信

(二)进程的管道通信实验实验目的1、了解什么是管道2、熟悉UNIX/LINUX支持的管道通信方式实验内容编写程序实现进程的管道通信。

用系统调用pipe()建立一管道,二个子进程P1和P2分别向管道各写一句话:

Child1issendingamessage!

Child2issendingamessage!

父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,后P2)。

实验指导一、什么是管道UNIX系统在OS的发展上,最重要的贡献之一便是该系统首创了管道(pipe)。

这也是UNIX系统的一大特色。

所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者消费者方式进行通信的一个共享文件,又称为pipe文件。

由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。

句柄fd[0]句柄fd[1]读出端写入端二、管道的类型:

1、有名管道一个可以在文件系统中长期存在的、具有路径名的文件。

用系统调用mknod()建立。

它克服无名管道使用上的局限性,可让更多的进程也能利用管道进行通信。

因而其它进程可以知道它的存在,并能利用路径名来访问该文件。

对有名管道的访问方式与访问其他文件一样,需先用open()打开。

2、无名管道一个临时文件。

利用pipe()建立起来的无名文件(无路径名)。

只用该系统调用所返回的文件描述符来标识该文件,故只有调用pipe()的进程及其子孙进程才能识别此文件描述符,才能利用该文件(管道)进行通信。

当这些进程不再使用此管道时,核心收回其索引结点。

二种管道的读写方式是相同的,本文只讲无名管道。

3、pipe文件的建立分配磁盘和内存索引结点、为读进程分配文件表项、为写进程分配文件表项、

分配用户文件描述符4、读/写进程互斥内核为地址设置一个读指针和一个写指针,按先进先出顺序读、写。

为使读、写进程互斥地访问pipe文件,需使各进程互斥地访问pipe文件索引结点中的直接地址项。

因此,每次进程在访问pipe文件前,都需检查该索引文件是否已被上锁。

若是,进程便睡眠等待,否则,将其上锁,进行读/写。

操作结束后解锁,并唤醒因该索引结点上锁而睡眠的进程。

三、所涉及的系统调用1、pipe()建立一无名管道。

系统调用格式pipe(filedes)参数定义intpipe(filedes);intfiledes[2];其中,filedes[1]是写入端,filedes[0]是读出端。

该函数使用头文件如下:

#includeunistd.h#inlcudesignal.h#includestdio.h2、read()系统调用格式read(fd,buf,nbyte)功能:

从fd所指示的文件中读出nbyte个字节的数据,并将它们送至由指针buf所指示的缓冲区中。

如该文件被加锁,等待,直到锁打开为止。

参数定义intread(fd,buf,nbyte);intfd;char*buf;unsignednbyte;3、write()系统调用格式read(fd,buf,nbyte)功能:

把nbyte个字节的数据,从buf所指向的缓冲区写到由fd所指向的文件中。

如文件加锁,暂停写入,直至开锁。

参数定义同read()。

五、运行结果六、思考题1、程序中的sleep(5)起什么作用?

2、子进程1和2为什么也能对管道进行操作?

实验三进程通信(三)消息的发送与接收实验实验目的1、了解什么是消息2、熟悉消息传送的机理实验内容消息的创建、发送和接收。

使用系统调用msgget(),msgsnd(),msgrev(),及msgctl()编制一长度为1k的消息发送和接收的程序。

实验指导一、什么是消息消息(message)是一个格式化的可变长的信息单元。

消息机制允许由一个进程给其它任意的进程发送一个消息。

当一个进程收到多个消息时,可将它们排成一个消息队列。

消息使用二种重要的数据结构:

一是消息首部,其中记录了一些与消息有关的信息,如消息数据的字节数;二个消息队列头表,其每一表项是作为一个消息队列的消息头,记录了消息队列的有关信息。

1、消息机制的数据结构

(1)消息首部记录一些与消息有关的信息,如消息的类型、大小、指向消息数据区的指针、消息队列的链接指针等。

(2)消息队列头表其每一项作为一个消息队列的消息头,记录了消息队列的有关信息如指向消息队列中第一个消息和指向最后一个消息的指针、队列中消息的数目、队列中消息数据的总字节数、队列所允许消息数据的最大字节总数,还有最近一次执行发送操作的进程标识符和时间、最近一次执行接收操作的进程标识符和时间等。

2、消息队列的描述符UNIX中,每一个消息队列都有一个称为关键字(key)的名字,是由用户指定的;消息队列有一消息队列描述符,其作用与用户文件描述符一样,也是为了方便用户和系统对消息队列的访问。

二、涉及的系统调用1.msgget()创建一个消息,获得一个消息的描述符。

核心将搜索消息队列头表,确定是否有指定名字的消息队列。

若无,核心将分配一新的消息队列头,并对它进行初始化,然后给用户返回一个消息队列描述符,否则它只是检查消息队列的许可权便返回。

系统调用格式:

msgqid=msgget(key,flag)该函数使用头文件如下:

#includesys/types.h#includesys/ipc.h#includesys/msg.h

参数定义intmsgget(key,flag)key_tkey;intflag;其中:

key是用户指定的消息队列的名字;flag是用户设置的标志和访问方式。

如IPC_CREAT|0400是否该队列已被创建。

无则创建,是则打开;IPC_EXCL|0400是否该队列的创建应是互斥的。

msgqid是该系统调用返回的描述符,失败则返回-1。

2.msgsnd()发送一消息。

向指定的消息队列发送一个消息,并将该消息链接到该消息队列的尾部。

系统调用格式:

msgsnd(msgqid,msgp,size,flag)该函数使用头文件如下:

#includesys/types.h#includesys/ipc.h#includesys/msg.h参数定义:

intmsgsnd(msgqid,msgp,size,flag)Iintmsgqid,size,flag;structmsgbuf*msgp;其中msgqid是返回消息队列的描述符;msgp是指向用户消息缓冲区的一个结构体指针。

缓冲区中包括消息类型和消息正文,即{longmtype;/*消息类型*/charmtext[];/*消息的文本*/}size指示由msgp指向的数据结构中字符数组的长度;即消息的长度。

这个数组的最大值由MSG-MAX()系统可调用参数来确定。

flag规定当核心用尽内部缓冲空间时应执行的动作:

进程是等待,还是立即返回。

若在标志flag中未设置IPC_NOWAIT位,则当该消息队列中的字节数超过最大值时,或系统范围的消息数超过某一最大值时,调用msgsnd进程睡眠。

若是设置IPC_NOWAIT,则在此情况下,msgsnd立即返回。

对于msgsnd(),核心须完成以下工作:

(1)对消息队列的描述符和许可权及消息长度等进行检查。

若合法才继续执行,否则返回;

(2)核心为消息分配消息数据区。

将用户消息缓冲区中的消息正文,拷贝到消息数据区;(3)分配消息首部,并将它链入消息队列的末尾。

在消息首部中须填写消息类型、消息大小和指向消息数据区的指针等数据;(4)修改消息队列头中的数据,如队列中的消息数、字节总数等。

最后,唤醒等待消息的进程。

3.msgrcv()接受一消息。

从指定的消息队列中接收指定类型的消息。

系统调用格式:

msgrcv(msgqid,msgp,size,type,flag)本函数使用的头文件如下:

#includesys/types.h#includesys/ipc.h#includesys/msg.h参数定义:

intmsgrcv(msgqid,msgp,size,type,flag)intmsgqid,size,flag;structmsgbuf*msgp;longtype;其中,msgqid,msgp,size,flag与msgsnd中的对应参数相似,type是规定要读的消息类型,flag规定倘若该队列无消息,核心应做的操作。

如此时设置了IPC_NOWAIT标志,则立即返回,若在flag中设置了MS_NOERROR,且所接收的消息大于size,则核心截断所接收的消息。

对于msgrcv系统调用,核心须完成下述工作:

(1)对消息队列的描述符和许可权等进行检查。

若合法,就往下执行;否则返回;

(2)根据type的不同分成三种情况处理:

type=0,接收该队列的第一个消息,并将它返回给调用者;type为正整数,接收类型type的第一个消息;type为负整数,接收小于等于type绝对值的最低类型的第一个消息。

(3)当所返回消息大小等于或小于用户的请求时,核心便将消息正文拷贝到用户区,并从消息队列中删除此消息,然后唤醒睡眠的发送进程。

但如果消息长度比用户要求的大时,则做出错返回。

4.msgctl()消息队列的操纵。

读取消息队列的状态信息并进行修改,如查询消息队列描述符、修改它的许可权及删除该队列等。

系统调用格式:

msgctl(msgqid,cmd,buf);本函数使用的头文件如下:

#includesys/types.h#includesys/ipc.h#includesys/msg.h参数定义:

intmsgctl(msgqid,cmd,buf);intmsgqid,cmd;structmsgqid_ds*buf;其中,函数调用成功时返回0,不成功则返回-1。

buf是用户缓冲

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 法律文书 > 调解书

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2