当前位置: 首页 > news >正文

实验一 进程控制实验

一、实验目的

1、掌握进程的概念,理解进程和程序的区别。

2、认识和了解并发执行的实质。

3、学习使用系统调用fork()创建新的子进程方法,理解进程树的概念。

4、学习使用系统调用wait()或waitpid()实现父子进程同步。

5、学习使用getpid()和getppid()获得当前进程和父进程的PID号。

6、掌握使用exec簇函数实现进程映像更换的方法。

7、了解系统编程,学习父进程如何通过创建一个子进程来完成某项特定任务的方法。

二、实验内容

1、进程的创建

    编写一段程序,使用系统调用fork( )创建两个子进程,在系统中有一个父进程和两个子进程活动。让每个进程在屏幕上显示一个字符;父进程显示字符“a”,子进程分别显示字符“b” 和“c”。试观察记录屏幕上的显示结果,并分析结果。(1分)

    <参考程序>

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/types.h>

int main()

{   int  p1, p2;

       while((p1=fork())==-1);

        if(p1==0)

            printf("b ");

        else

        {   while((p2=fork())==-1);

            if(p2==0)

                printf("c ");

            else

                printf("a ");

        }

        return 0;

}

执行结果及结果分析:

shell窗口也是一个进程,所以看到4个进程信息,一个父进程,二个子进程和一个shell进程。先是父进程输出a, 子进程1输出b,之后是子进程2输出c,之后输出shell窗口提示符。

  1. 修改第一题,在父进程中显示当前进程识别码,在每个子进程中显示当前进程识别码和父进程识别码,运行程序查看结果,分析运行结果。

试做:

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/types.h>

int main()

{   int  p1, p2;

    while((p1=fork())==-1);

    if(p1==0)    //p1子进程

        printf("b: pid=%d ppid=%d\n",getpid(),getppid());

    else        //父进程

    {   while((p2=fork())==-1);

        if(p2==0)//p2子进程

            printf("c: pid=%d ppid=%d\n",getpid(),getppid());

        else     //父进程

            printf("a: pid=%d\n",getpid());

    }

        return 0;

}

运行结果:

结果分析:

先打印父进程 然后创建第一个子进程p1,然后父进程创建第二个子进程p2,如果不想让父进程在子进程结束之前结束,可以用wait(0)让父进程等待子进程结束,之后父进程再结束。2个wait(0)是因为有2个子进程要等待。

  1. 改进第二题,使父进程等待两个子进程结束之后再结束。

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/types.h>

int main()

{   int  p1, p2;

    while((p1=fork())==-1);

    if(p1==0)

        printf("b:pid=%d ppid=%d\n",getpid(),getppid());

    else

    {   while((p2=fork())==-1);

        if(p2==0)

            printf("c:pid=%d ppid=%d\n",getpid(),getppid());

        else

            {

wait(0);

wait(0);

                printf("a:pid=%d\n",getpid());

            }

    }

        return 0;

}

运行结果:

从上述子进程和父进程识别码可以看出父子进程之间的关系。


 

图1进程树的参考程序:

#include<stdio.h>

#include<unistd.h>

int main()

{

    int  p1,p2,p3;

    while((p1=fork())== -1);

    if(p1==0)

    {

        while((p2=fork())==-1);       

        if(p2==0)

        {

            while((p3=fork())==-1);       

            if(p3==0)   //p3子进程

                printf(" d,Mypid=%d, myppid=%d\n", getpid(), getppid());

             else   //p2子进程

                printf(" c,Mypid=%d, myppid=%d\n", getpid(), getppid());

        }

        else //p1子进程

        printf(" b,Mypid=%d, myppid=%d\n", getpid(), getppid());

    }

    else //主进程

        printf(" a,Mypid is %d\n", getpid());

getchar();

}

编译及执行程序:

结果截屏:

  1. 模仿第2题,按图2进程树编写程序,给出编译及执行过程和结果截屏。(1分)

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/wait.h>

int main() {

    pid_t a, b, c, d, e;

    a = fork();

    if (a < 0) {

        perror("fork");

        exit(1);

    }

    if (a == 0) {

        printf("I am process A\n");

        b = fork();

        if (b < 0) {

            perror("fork");

            exit(1);

        }

        if (b == 0) {

            printf("I am process Bn");

            c = fork();

            if (c < 0) {

                perror("fork");

                exit(1);

            }

            if (c == 0) {

                printf("I am process C\n");

            } else {

                printf("I am process B, and my child is process C\n");

                wait(NULL);

            }

        } else {

            printf("I am process A, and my child is process B\n");

            wait(NULL);

        }

    } else {

        d = fork();

        if (d < 0) {

            perror("fork");

            exit(1);

        }

        if (d == 0) {

            printf("I am process Dn");

            e = fork();

            if (e < 0) {

                perror("fork");

                exit(1);

            }

            if (e == 0) {

                printf("I am process E\n");

            } else {

                printf("I am process D, and my child is process E\n");

                wait(NULL);

            }

        } else {

            printf("I am process A, and my child is process D\n");

            wait(NULL);

        }

    }

    return 0;

}

结果截屏:

  1. 分析程序,给出编译及执行过程和结果截屏。(2分)
  1. #include<unistd.h>

#include<stdlib.h>

#include<stdio.h>

#include <sys/wait.h>

int main()

{   int child,p;

        while((child=fork())==-1);

        if(child==0)    //子进程下

        {   printf("In child: sleep for 10 seconds and then exit. \n");

            sleep(10);

            exit(0);

        }

        else    //父进程下

        {   do

            {   p=waitpid(child,NULL,WNOHANG);  //非阻塞式等待子进程结束

                if(p==0)

                {   printf("In father: The child process has not exited.\n");

                   sleep(1);

                }

            }while(p==0);

            if(p==child)

            {   printf("Get child exitcode then exit!\n");}

            else

            {   printf("Error occured!\n");}

        }

        exit(0);

}

编译及执行过程和运行结果截屏:

分析程序功能:

该程序的功能是创建一个子进程,并在子进程中睡眠10秒后退出,父进程不阻塞地等待子进程结束并获取退出状态码,然后退出。

2) #include<unistd.h>

#include<stdlib.h>

#include<stdio.h>

main()

{   int child,p;

        while((child=fork())==-1);

        if(child==0)    //子进程下

        {   execl("/home/student/welcome.out","",NULL);

            exit(0);

        }

        else    //父进程下

        {   p=waitpid(child,NULL,0);  //阻塞式等待子进程结束  

if(p==child)

printf("Get child exitcode then exit!\n");

else

                printf("Error occured!\n");

        }

exit(0);

}

子进程要加载程序的源程序welcome.c

#include<stdio.h>

main()

{   printf("Hello! This is another process.\n");}

编译及执行过程和运行结果截屏:

5. 编程创建2个子进程,子进程1运行指定路径下的可执行文件(如:/home/student/welcome.out),子进程2暂停10s之后退出,父进程先用阻塞方式等待子进程1的结束,然后用非阻塞方式等待子进程2的结束,待收集到二个子进程结束的信息,父进程就返回。(2分)

参考程序框架:

#include<unistd.h>

#include<stdlib.h>

#include<stdio.h>

#include<sys/wait.h>

int main()

{   int child1,child2,p;

    while((child1=fork())==-1);

    if(child1==0)   //child1置换进程

    {

         execl("/home/gzh0624/welcome.o","welcome.o",NULL);

         perror("execl");

         exit(0);

      }

    else    //father

    {   while((child2=fork())==-1);

        if(child2==0)   //child2暂停10秒退出

        {  

                    sleep(10);

                    exit(0);

          }

        else    //father等待子进程结束

        {   p=waitpid(child1,NULL,0);//阻塞式等待子进程1结束  

            if(p==child1)

                printf("Get child1 exitcode then exit!\n");

            else

                printf("Error occured!\n");

            do

            {p=waitpid(child2,NULL,WNOHANG);//非阻塞式等待子进程2结束

                if(p==0)

                {  

                   printf("In father: The child2 process has not exited.\n");

                   sleep(1);

                }

            }while(p==0);

            if(p==child2)  

                printf("Get child2 exitcode then exit!\n");

            else   

                printf("Error occured!\n");

        }

    }

    exit(0);

}编译及执行过程:

结果截屏:

分析程序功能:

程序的功能是创建两个子进程,其中一个子进程调用另一个可执行文件welcome.o,另一个子进程暂停10秒后退出。父进程等待子进程结束,并打印相应的信息。

  1. 编写一个简易的shell解释程序。其运行原理是:当命令行上有命令需要执行时,shell进程获得该命令,然后创建子进程,让子进程执行该命令,shell进程等待子进程退出,之后继续等待命令行上的命令周而复始。(附加题)

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/wait.h>

#include <string.h>

#define MAX_CMD_LENGTH 100

void execute_command(char *command) {

    pid_t pid;

    pid = fork();

    if (pid < 0) {

        fprintf(stderr, "Fork failed\n");

        exit(1);

    } else if (pid == 0) { // Child process

        char *args[MAX_CMD_LENGTH];

        // Split the command into arguments

        char *token = strtok(command, " ");

        int i = 0;

        while (token != NULL) {

            args[i++] = token;

            token = strtok(NULL, " ");

        }

        args[i] = NULL;

        // Execute the command

        execvp(args[0], args);

        // If execvp returns, there was an error

        fprintf(stderr, "Command not found: %s\n", args[0]);

        exit(1);

    } else { // Parent process

        int status;

        waitpid(pid, &status, 0);

    }

}

int main() {

    char command[MAX_CMD_LENGTH];

    while (1) {

        printf("shell> ");

        fgets(command, MAX_CMD_LENGTH, stdin);

        // Remove new line character

        command[strcspn(command, "\n")] = 0;

        // Check if user wants to exit

        if (strcmp(command, "exit") == 0) {

            break;

        }

        execute_command(command);

    }

    return 0;

}

编译及执行过程:

结果截屏:

三、实验总结和体会

  在本次实验中,我们深入学习并实践了Linux进程控制的相关知识和技术。通过对进程创建、销毁、管理等操作的实践,我对Linux进程控制有了更加深入的理解和掌握。

首先,通过实验,我学会了如何创建新的进程。我们使用了fork()系统调用,它可以创建一个与原进程几乎完全相同的新进程,包括代码、数据、运行时堆栈等。我们还学习了如何在新的进程中执行不同的代码,以实现不同的功能。

其次,我学会了如何控制进程的执行。通过实验中的信号处理,我们可以向进程发送信号,从而实现对进程的控制。我们学习了不同的信号及其对应的处理方式,如SIGINT、SIGKILL、SIGSTOP等。通过实验,我更加了解了信号的工作原理和使用方法。

此外,我还学会了如何管理进程的资源。通过实验中的共享内存和进程间通信,我们可以实现不同进程之间的数据传递和共享。我们学习了共享内存的创建、映射和销毁等操作,以及如何使用信号量进行进程间的同步和互斥。

通过这次实验,我深刻体会到了进程控制在操作系统中的重要性。进程是操作系统中最基本的运行单位,掌握好进程控制的知识和技术对于编程和系统管理都非常重要。通过实践,我对Linux进程控制有了更加深入的理解,并且进一步培养了自己的编程能力和解决问题的能力。

http://www.xdnf.cn/news/84259.html

相关文章:

  • 《构建通用学习体系:从底层逻辑到场景应用》
  • Python 基础
  • Trent硬件工程师培训完整135讲
  • Java基础复习(JavaSE进阶)第六章 IO流体系
  • DCDC芯片,boost升压电路设计,MT3608 芯片深度解析:从架构到设计的全维度技术手册
  • 已安装爱思助手和Apple相关驱动,但仍无法有线连接iPhone热点,且网络适配器没有Apple Mobile Device Ethernet,问题解决
  • MySQL索引知识点(笔记)
  • 如何Ubuntu 22.04.5 LTS 64 位 操作系统部署运行SLAM3! 详细流程
  • 【数据结构】第五弹——Stack 和 Queue
  • chili3d调试笔记8 打印零件属性
  • docker 常见命令
  • yarn的介绍与操作,yarn和npm的选择
  • AI 健康小屋:开启智慧健康管理新范式
  • Jetson Orin NX 16G 配置GO1强化学习运行环境
  • JavaFX实战:从零到一实现一个功能丰富的“高级反应速度测试”游戏
  • VSCode连服务器一直处于Downloading
  • 【C++】特殊类的设计、单例模式以及Cpp类型转换
  • MCP使用SSE和STDIO模式时,mcp client 如何连接
  • 【随手记】jupyter notebook绘制交互式图像
  • Element UI、Element Plus 里的表单验证的required必填的属性不能动态响应?
  • Anaconda、conda和PyCharm在Python开发中各自扮演的角色
  • Docker 中运行 JAR 文件
  • std::vector 自定义分配器
  • 第六章 QT基础:2、编程基础及串口助手案例
  • 一文读懂什么是 MCP、A2A、ANP
  • TypeScript十大关键语法
  • 第44讲:玩转土壤数据!用机器学习挖掘地球皮肤的秘密 [特殊字符][特殊字符]
  • 集成算法学习案例
  • Open GL ES -> 模版测试,绘制SurfaceView中某个目标区域
  • 【目标检测】对YOLO系列发展的简单理解