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);/*关闭文件*/
}

此代码编译会有报警,不用管,没有错误就可以正常运行。

运行结果如下图

 

(本人用的Linux为centos 7 ,若Debian系统运行出错,可以百度自己的问题)

posted @ 2020-05-21 10:54  Cool-baby  阅读(60)  评论(0)    收藏  举报