当前位置: 首页 > 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进程控制有了更加深入的理解,并且进一步培养了自己的编程能力和解决问题的能力。

相关文章:

  • 2023蓝帽杯初赛内存取证-4
  • NVIDIA 自动驾驶技术见解
  • 从零到多智能体:Google Agent开发套件(ADK)入门指南
  • C语言教程(十三):C 语言中 enum(枚举)的详细介绍
  • 武装Burp Suite工具:RouteVulScan插件_被动扫描发现漏洞.
  • shared_ptr八股收集 C++
  • SwiftInfer —— 大模型无限流式输入推理打破多轮对话长度限制
  • 【题解-Acwing】847. 图中点的层次
  • 双指针之有序数组的平方
  • 航电系统之自动控制系统篇
  • MulanPSL-1.0开源协议
  • 衡石ChatBI:依托开放架构构建技术驱动的差异化数据服务
  • 该虚拟机似乎正在使用中。如果该虚拟机未在使用,请按“获取所有权(T)”按钮获取它的所有权。否则,请按“取消(C)”按钮以防损坏解决方法
  • VSCode中安装GitGraph
  • 3.6/Q1,Charls数据库经典文章解读
  • Python设计模式:对象池
  • 金融数据分析(Python)个人学习笔记(11):回归分析
  • el-popover实现下拉滚动刷新
  • Java1.8原生http 与SSM Jetty性能对比
  • 数据库MySQL学习——day1(创建表与数据类型)
  • 神二十具备执行发射任务的各项条件
  • 税率飙至3500%!美国双反大棒重击东南亚光伏,中企如何应对
  • 教皇方济各逝世,外交部:表示哀悼,愿同梵方共同推动中梵关系持续改善
  • 山西一国道塌陷致2死后续:地质雷达检测出10处道路病害
  • 专家学者视角下的乡村教育:目标与出路并非“走出大山”
  • 2025年上海车展后天开幕,所有进境展品已完成通关手续