一、 实验目的
1、掌握进程的概念,明确进程的含义。
2、认识并了解进程并发执行的实质,进程的阻塞与唤醒,终止与退出的过程。
3、熟悉进程的睡眠、同步、撤消等进程控制方法。
4、分析进程竞争资源的现象,学习解决进程互斥的方法 。
5、了解什么是信号,利用信号量机制熟悉进程间软中断通信的基本原理,
6、熟悉消息传送的机理 ,共享存储机制 。
二、 实验内容
1、编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程并发执行,观察实验结果并分析原因。
2、用fork( )创建一个进程,再调用exec( ),用新的程序替换该子进程的内容,利用wait( )来控制进程执行顺序,掌握进程的睡眠、同步、撤消等进程控制方法,并根据实验结果分析原因。
3、编写一段多进程并发运行的程序,用lockf( )来给每一个进程加锁,以实现进程之间的互斥,观察并分析出现的现象及原因。
4、编写程序:用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
Child process1 is killed by parent!
Child process2 is killed by parent!
父进程等待两个子进程终止后,输出如下的信息后终止:
Parent process is killed!
分析利用信号量机制中的软中断通信实现进程同步的机理。
5、使用系统调用msgget( ),msgsnd( ),msgrev( ),及msgctl( )编制一长度为1k的消息发送和接收的程序,并分析消息的创建、发送和接收机制及控制原理。
6、编制一长度为1k的共享存储区发送和接收的程序,并设计对该共享存储区进行互斥访问及进程同步的措施,必须保证实现正确的通信。
7、编写程序实现进程的管道通信。用系统调用pipe( )建立一管道,二个子进程P1和P2分别向管道各写一句话:
Child 1 is sending a message!
Child 2 is sending a message!
父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,后P2),分析管道通信机制及控制原理。
三、实验原理
略
四、实验中用到的系统调用函数(包括实验原理中介绍的和自己采用的),自己采用的系统调用函数要按照指导书中的格式说明进行介绍。
本实验的用到的主要系统调用函数:
Fork, exec, wait, exit, getpid, sleep, lockf, kill, signal, read, write, msgget, msgsnd, msgrcv, msgctl,shmget, shmat, shmdt, shmctl,pipe。
五、实验步骤
1、父进程通过fork()系统调用创建两个子进程,如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。三个进程并发执行,将fork()函数的返回值赋于两个变量pid1和pid2,父进程输出“父进程”,两个子进程分别输出“子进程1”和“子进程2”,三个进程的输出有随机性。
2、父进程创建一个子进程,如果子进程创建成功,若此时是父进程正在运行,则父进程用wait()来进行等待操作,将CPU交给子进程,子进程获得CPU后,开始运行,用系统中bin目录下的ls命令程序装入子进程运行的地址,即用ls命令程序代替子进程。当子进程运行完毕,父进程继续运行输出,程序运行完毕。
3、父进程创建两个子进程,若是父进程运行,则输出parent 0、parent1、parent2、parent3,若子进程运行,则输出son0、son1、son2、son3或daughter0、daughter1、daughter2、daughter3。给父进程和两个子进程都加上锁,保证其中的一个在占用资源时不会被别的进程干扰。
4、利用信号软中断机制,开始时两个子进程都保持阻塞,直到父进程向子进程发送软中断信号,父进程进入阻塞状态,子进程才能继续运行,输出“child process1 is killed by parent!” “child process2 is killed by parent!” ,子进程执行后,父进程继续执行,输入“parent process is kiled!”。
5、当进程要发消息给另一个进程时,会先向系统申请一个缓冲区,把消息写进去,接着把该缓冲区连接到接受方的一个消息队列中,并通知接受者,接收方进程可以从消息队列中取出消息,并释放缓冲区。思路是建立一个服务端负责接收消息,这个服务端要创建一个消息队列,服务器端可以从中取出消息;再建立一个客户端,将消息写入消息队列中,达到发送消息的效果。
6、我们首先要创建一个共享存储区,然后两个进程按序依次进行读写操作,服务端总是设置该存储区取值为-1,只有存储区取值为-1时客户端才可以对存储区进行修改,服务端在不是-1的情况下可以接收信息,并且在接收信息后存储区要重新赋值-1。
7、首先创建一个管道,定义两个数组outpipe、inpipe来存放写入管道和从管道读出的数据,父进程用fork( )创建两个子进程,子进程用write( )向管道中写入数据,父进程用read( )从管道中读取数据,再输出到屏幕上。通过加锁互斥并发运行使父进程从管道中先接收子进程1的信息,再接收子进程2 的信息。
六、实验数据及源代码(学生必须提交自己设计的程序源代码,并有注释,源代码电子版也一并提交),包括思考题的程序。
1、
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
pid_t pid1,pid2; //进程标识符
pid1 = fork(); //创建一个新的进程
if(pid1<0)
{
printf("创建进程失败!");
exit(1);
}
else if(pid1==0) //如果pid为0则表示当前执行的是子进程
{
printf("子进程1");
}
else //否则为父进程
{
pid2 = fork();//創建一個新的进程
if(pid2<0)
{
printf("创建进程失败!");
exit(1);
}
else if(pid2==0) //如果pid为0则表示当前执行的是子进程
{
printf("子进程2");
}
else //否则为父进程
{
printf("父进程");
}
}
return 0;
}
2、
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
int main()
{
int pid;
pid=fork( ); /*创建子进程*/
if(pid==-1) /*进程创建失败*/
{
printf("进程创建失败\n");
exit(1);
}
else if(pid==0) /*子进程运行*/
{
execl("/bin/ls","ls","-l",(char*)0);
printf("执行失败\n");
exit(1);
}
else /*父进程*/
wait(NULL); /*同步*/
printf("程序执行完毕\n");
exit(0);
}
3、
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main(int argc,char* argv[])
{
int p1,p2,i;
p1=fork(); //创建进程
p2=fork();
if(p1==0)
{
lockf(1,1,0); //加锁
for(i=0;i<4;i++)
{
printf("parent %d\n",i);
}
lockf(1,0,0); //解锁
wait(0); //保证子进程终止前,父进程不终止
exit(0);
}
else
{
if(p2==0)
{
lockf(1,1,0); //加锁
for(i=0;i<4;i++