实验一 进程控制实验

一、实验目的

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.mzph.cn/news/902440.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python Web开发】01-Socket网络编程01

文章目录 1.套接字(Socket)1.1 概念1.2 类型1.3 使用步骤 Python 的网络编程主要用于让不同的计算机或者程序之间进行数据交换和通信&#xff0c;就好像人与人之间打电话、发消息一样。 下面从几个关键方面通俗易懂地介绍一下&#xff1a; 1.套接字(Socket) 在 Python 网络编…

Git 配置 GPG 提交签名

使用 GPG 对 Git 提交进行签名&#xff0c;可以证明该提交确实是你本人提交的。这在团队协作和代码审核中非常有用&#xff0c;GitHub/GitLab 等平台也会显示 “Verified” 标签。 &#x1f9e9; 一、检查是否已安装 GPG gpg --version 如果未安装&#xff0c;可使用以下命令…

MySQL运维三部曲初级篇:从零开始打造稳定高效的数据库环境

文章目录 一、服务器选型——给数据库一个舒适的家二、系统调优——打造高性能跑道三、MySQL配置——让数据库火力全开四、监控体系——数据库的体检中心五、备份恢复——数据安全的最后防线六、主从复制——数据同步的艺术七、安全加固——守护数据长城 引言&#xff1a;从小白…

实践项目开发-hbmV4V20250407-跨平台开发框架深度解析与VSCode一站式开发实践

跨平台开发框架深度解析与VSCode一站式开发实践 在当今多端应用开发需求激增的背景下&#xff0c;跨平台开发框架成为了众多开发者的首选。本文将围绕React Native、Taro及其结合方案&#xff0c;以及Uni-app、MUI、Quasar等轻量级框架展开详细分析&#xff0c;并探讨如何在VS…

Android15沉浸式界面顶部有问题

Android15沉浸式界面顶部有问题 往往开发人员的手机没这么高级&#xff0c;客户或者老板的手机是Android15的。 我明明就设了状态栏透明&#xff0c;我的手机也没问题。但Android15是有问题的。 先看下有问题的界面&#xff1a; 解决方案&#xff1a; 处理1&#xff1a; if (…

uni-app 状态管理深度解析:Vuex 与全局方案实战指南

uni-app 状态管理深度解析&#xff1a;Vuex 与全局方案实战指南 一、Vuex 使用示例 1. 基础 Vuex 配置 1.1 项目结构 src/ ├── store/ │ ├── index.js # 主入口文件 │ └── modules/ │ └── counter.js # 计数器模块 └── main.js …

【STM32单片机】#11 I2C通信(软件读写)

主要参考学习资料&#xff1a; B站江协科技 STM32入门教程-2023版 细致讲解 中文字幕 开发资料下载链接&#xff1a;https://pan.baidu.com/s/1h_UjuQKDX9IpP-U1Effbsw?pwddspb 单片机套装&#xff1a;STM32F103C8T6开发板单片机C6T6核心板 实验板最小系统板套件科协 实验&…

每天一道面试题@第一天

1&#xff1a;TCP和UDP的区别&#xff0c;TCP为什么是三次握手&#xff0c;不是两次&#xff1f; 因为TCP是全双工协议&#xff0c;区别在于TCP可靠&#xff0c;UDP不可靠&#xff0c;效率更高。 详解&#xff1a; TCP&#xff08;传输控制协议&#xff09;和 UDP&#xff08;…

一款强大的实时协作Markdown工具 | CodiMD 9.6K ⭐

CodiMD 介绍 CodiMD 是一个开源的实时协作 Markdown 笔记工具&#xff0c;它允许用户在任何平台上共同编辑 Markdown 文档。核心功能是实时协作&#xff0c;它允许多个用户同时编辑同一个文档&#xff0c;并实时看到彼此的更改。支持实时渲染预览&#xff0c;支持超多的富文本格…

若依如何切换 tab 不刷新

方法 如上图配置 菜单中选是否缓存&#xff1a;缓存 资料 前端手册 |RuoYi:

【浙江大学DeepSeek公开课】回望AI三大主义与加强通识教育

回望AI三大主义与加强通识教育 一、人工智能三大主义二、人工智能发展历程三、从 ChatGPT 到 DeepSeek四、人工智能通识教育五、人工智能的挑战与未来 一、人工智能三大主义 符号主义 &#xff1a;逻辑推理&#xff0c;将推理视为计算过程。如苏格拉底三段论&#xff0c;通过前…

边缘计算全透视:架构、应用与未来图景

边缘计算全透视&#xff1a;架构、应用与未来图景 一、产生背景二、本质三、特点&#xff08;一&#xff09;位置靠近数据源&#xff08;二&#xff09;分布式架构&#xff08;三&#xff09;实时性要求高 四、关键技术&#xff08;一&#xff09;硬件技术&#xff08;二&#…

C++——多态、抽象类和接口

目录 多态的基本概念 如何实现多态 在C中&#xff0c;派生类对象可以被当作基类对象使用 编程示例 关键概念总结 抽象类 一、抽象类的定义 基本语法 二、抽象类的核心特性 1. 不能直接实例化 2. 派生类必须实现所有纯虚函数才能成为具体类 3. 可以包含普通成员函数和…

初级达梦dba的技能水准

在x86环境&#xff08;windows、linux&#xff09;安装单机软件&#xff0c;安装客户端创建过至少20套数据库&#xff0c;优化参数并更新过正式许可会用逻辑导出导入以及dmrman备份了解manager工具的使用配置sqllog日志&#xff0c;并能解释输出内容能够分析因磁盘空间不足、内…

监控页面卡顿PerformanceObserver

监控页面卡顿PerformanceObserver 性能观察器掘金 const observer new PerformanceObserver((list) > {}); observer.observe({entryTypes: [longtask], })

智能座舱测试内容与步骤

智能座舱的测试步骤通常包括以下环节&#xff1a; 1.测试环境搭建与准备 • 硬件需求分析&#xff1a;准备测试车辆、服务器与工作站、网络设备以及传感器和执行器模拟器等硬件设备。 • 软件需求分析&#xff1a;选择测试管理软件、自动化测试工具、模拟软件和开发调试工具等。…

Redis——网络模型

目录 前言 1.用户空间和内核空间 1.2用户空间和内核空间的切换 1.3切换过程 2.阻塞IO 3.非阻塞IO 4.IO多路复用 4.1.IO多路复用过程 4.2.IO多路复用监听方式 4.3.IO多路复用-select 4.4.IO多路复用-poll 4.5.IO多路复用-epoll 4.6.select poll epoll总结 4.7.IO多…

电力系统中为什么采用三相交流电?

电力系统中为什么采用三相交流电 电力系统中采用三相交流电&#xff0c;主要是因为它在输电效率、设备使用、能量传输平稳性等方面相比单相交流或直流电具有显著优势。下面我详细解释一下原因&#xff1a; &#x1f31f; 1. 提高输电效率&#xff08;节省电缆材料&#xff09;…

python简介与入门

目录 python初始 python的优势 python的特性 python的应用领域 Linux环境中安装python 下载python3.11.6 安装依赖包 解压python压缩包 安装python 编译及安装 建立软连接 测试python3运行 设置国内pip更新源 更新pip版本&#xff08;必须更新&#xff09; wind…

Web内网渗透知识大全

内网渗透 端口转发 需要三个主机&#xff0c;Windows7、Windows2016、kali Windows7为内网主机 Windows2016为跳板机 kali为攻击机 使用到的工具 netsh、MSF 我们先在Windows7上开启一个80服务&#xff0c;而这个80服务只能由Windows2016访问&#xff0c;kali不能访问 我们…