Linux进程管理
1 实验目的
1、加深对进程概念的理解,明确进程和程序的区别
2、进一步认识并发执行的实质
3、分析进程争用资源的现象,学习解决进程互斥的方法
2 背景知识
要用到的系统调用
1、int fork( )创建一个新进程
头文件:#include <sys/types.h>
#include <unistd.h>
返回值的意义: 0,创建子进程,从子进程返回的id值
-1,创建失败
大于0,从父进程返回的子进程id值
2、lockf(files, function, size)锁定/解锁文件或文件的某段
该函数的头文件为:#include <unistd.h>
参数定义: int lockf(int files, int function, long size)
含义: files是文件描述符;
function为1(常量F_LOCK)表示互斥锁定,为0(常量F_ULOCK)表示解锁;
size是锁定或解锁的字节数,若用0,表示从文件的当前位置到文件尾。
3实验内容
1、创建进程。
#include<stdio.h>
int main()
{
int pid;
pid = fork();
switch(pid)
{
case -1:
printf("fail to create process\n");
return 1;
case 0: //对于子进程来讲,变量pid的值为0
printf("I'm son, my pid is %d, my father's pid is %d\n", getpid(), getppid());
break;
default: //对于父进程来讲,pid记录了返回的子进程的ID,必然大于0
printf("I'm father, my pid is %d, my son's pid is %d\n", getpid(), pid);
}
return 0;
}
输出结果并非是一行,而是2行。比如,结果可能是:
I'm son, my pid is 1860, my father's pid is 1859
I'm father, my pid is 1859, my son's pid is 1860
解释:
fork函数被调用一次但返回两次。两次返回的唯一区别:子进程中返回0值,父进程中返回子进程ID。
为什么返回两次?原因:linux将父进程的地址空间、数据空间、堆、栈等资源复制一份给子进程,子进程是父进程的副本,只有代码段是共享的。注意:由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。不同的是,fork()返回给父进程的是新建子进程的ID,返回给子进程的是0。
如果对“返回”还难以理解,想一下学C语言时候的函数调用。函数调用时,将返回地址入栈,再将实参入栈。被调函数从栈中取出参数,赋值给形参,执行完后,取出返回地址,跳回去继续执行。
2、验证进程并发执行
编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每个进程在屏幕上显示一个字符串:父进程显示“parent is working”;两个子进程分别显示“son is working”和“daughter is working”。多运行几次该程序,观察屏幕上的显示结果,并分析原因。
<程序1如下> 文件名为a21.c
#include <stdio.h>
int main()
{
int p1,p2;
while((p1=fork())==-1); /*创建子进程,将其ID号给p1,直到成功*/
if(p1==0)
printf("son is working\n"); /*子进程返回的p1才为0,说明此时子进程执行*/
else /*p1>0,说明此p1是父进程函数调用返回的子进程的ID号*/
{
while((p2=fork())==-1); /*创建子进程p2,将其ID号给p2,直到成功*/
if(p2==0)
printf("dauthter is working"); /*子进程p2执行*/
else printf("parent"); /*父进程执行*/
}
printf("share\n");/*3个进程共享的语句*/
return 0;
}
执行:用gcc a21.c –o a21.out编译,产生a21.out文件。在终端里输入./a21.out,并回车执行。看结果。再按向上箭头,并回车重复执行。看结果。如此多执行几次。
分析:可以认为,父进程和两个子进程有相同的代码。相当于,上述程序有3份在内存。它们并发执行,但它们返回的ID不同,因此执行不同的分支语句。从进程并发执行来看,输出有多种情况。可能是son在前,也可能是parent或daughter在前。大多数情况下,son先输出。
原因:fork()创建进程所需的时间可能要多于输出一个字符串的时间,因此在主进程创建进程p2的这段时间可能有中断,进程p1就输出了son is working。
<程序2如下>文件名为a22.c
#include <stdio.h>
int main()
{
int p1,p2,i;
while((p1=fork())==-1); /*创建子进程,将其ID号给p1,直到成功*/
if(p1==0)
{
for(i=0;i<10;i++)
{
printf("son %d\n",i); /*子进程执行*/
}
}
else /*p1>0,说明此p1是父进程函数调用返回的子进程的ID号*/
{
while((p2=fork())==-1); /*创建子进程p2,将其ID号给p2,直到成功*/
if(p2==0){
for(i=0;i<10;i++)
printf("dauthter %d\n",i); /*子进程p2执行*/
}
else
{
printf("parent %d\n",i);
} /*父进程执行*/
}
return 0;
}
执行程序并分析结果:进程中的循环会由于进程被中断而中断,但字符串内部的字符顺序保持不变。同程序1一样,多进程是随机的,故,输出的字符串的顺序会有不同结果。
3、进程的控制
<程序3如下>文件名为a23.c
#include<stdio.h>
#include<unistd.h>
main()
{
int p1,p2,i,*fp;
fp=fopen("to_be_locked.txt","w+"); /*新建文件to_be_locked.txt,并打开*/
if(fp==NULL)
{
printf("Fail to create file");
exit(-1);
}
while((p1=fork())==-1); /*创建子进程p1*/
if(p1==0)
{
lockf(*fp,1,0); /*对文件加锁*/
for(i=0;i<10;i++)
fprintf(fp,"son %d\n",i); /*输出到文件*/
lockf(*fp,0,0); /*对文件解锁*/
}
else
{
while((p2=fork())==-1); /*创建子进程p2*/
if (p2==0)
{
lockf(*fp,1,0); /*加锁*/
for(i=0; i<10;i++)
fprintf(fp,"daughter %d\n",i); /*输出到文件*/
lockf(*fp,0,0); /*解锁*/
}
else
{
wait(NULL);
lockf(*fp, 1, 0); /*加锁*/
for(i = 0; i < 10; i++)
fprintf(fp,"parent %d\n",i); /*输出到文件*/
lockf(*fp,0,0); /*解锁*/
}
}
fclose(fp);/*关闭文件*/
}
此代码编译会有报警,不用管,没有错误就可以正常运行。
运行结果如下图

浙公网安备 33010602011771号