Linux操作系统实验十一 进程管理(上)

简介: Linux操作系统实验十一 进程管理

1.实验目的与要求

  1. 知道进程相关概念
  2. 获取进程信息
  3. 会进程的创建和终止
  4. 会进程的调用

2.实验平台

实验室安装的实验环境(Linux操作系统)和头歌(www.educoder.net)实验平台(课程实验)

3.实验内容

  1. 获取进程
  2. 进程的创建和终止
  3. 进程的调用

4.实验详细内容、步骤

任务描述

Linux 环境下,进程是一个十分重要的概念。每个进程都由一个唯一的标识符来表示,即进程ID,通常称为pid。本关将介绍如何获取进程的pid

本关任务:学会使用C语言在Linux系统中获取进程的pid以及父进程的pid

相关知识

Linux系统中存在一个特殊的进程,即空闲进程(idle process),当没有其他进程在运行时,内核所运行的进程就是空闲进程,它的pid0。在启动后,内核运行的第一个进程称为init进程,它的pid1。通常,Linux系统中init进程就是我们在资源管理器中看到的名为init的程序。系统中其它的进程都是由init来创建出来的。

创建新进程的那个进程被称为父进程,而新创建的进程被称为子进程。每个进程都是由其他进程创建的(除了init进程),因此每个子进程都有一个父进程。

Linux系统提供了两个系统调用函数来获取一个进程的pid和其父进程的pid,分别是getpidgetppid函数。在Linux系统中可以使用man命令来查询这些函数的使用方法。具体的查询命令为: man 2 函数名

获取进程自身pid

获取进程本身的进程ID的系统调用函数是getpid,具体的说明如下:

  • 需要的头文件如下:
  • i. #include <sys/types.h>
  • ii. #include <unistd.h>
  • 函数格式如下: pid_t getpid(void);
  • 函数返回值说明: 返回当前进程的pid值。

案例演示1: 编写一个程序,打印自身的进程ID。详细代码如下所示:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>

  4. int main()
  5. {
  6.    pid_t pid = getpid();
  7.    printf("当前进程的ID为:%d\n", pid);
  8.    
  9.    return 0;
  10. }

将以上代码保存为getpid.c文件,编译执行。可以看到每次运行都打印出不同的进程ID,这是因为Linux系统动态的给进程分配pid

获取父进程pid

获取父进程的进程ID的系统调用函数是getppid,具体的说明如下:

  • 需要的头文件如下:
  • i. #include <sys/types.h>
  • ii. #include <unistd.h>
  • 函数格式如下: pid_t getppid(void);
  • 函数返回值说明: 返回当前进程的父进程的pid值。

案例演示1: 编写一个程序,打印父进程ID和自身进程ID。详细代码如下所示:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>

  4. int main()
  5. {
  6.    pid_t pid = getpid();
  7.    printf("当前进程的ID为:%d\n", pid);
  8.    pid_t ppid = getppid();
  9.    printf("当前进程的父进程ID为:%d\n", ppid);
  10.    
  11.    return 0;
  12. }

将以上代码保存为getppid.c文件,编译执行。可以看到每次运行都打印出相同的父进程ID,这是因为我们在同一个终端中运行3次程序,所以被运行的程序父进程为终端进程,因为父进程一直都一样。

编程要求

本关的编程任务是补全右侧代码片段中BeginEnd中间的代码,具体要求如下:

  • 补全getProcInfo函数,用于获取当前进程ID和其父进程ID(提示:将结果存放在procIDInfo结构体中)。

测试说明

本关的测试需要用户在右侧代码页中补全代码,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。

任务描述

在上一关我们学习如何获取进程的pid信息,本关我们将介绍如何编程创建一个新的进程。

本关任务:学会使用C语言在Linux系统中使用fork系统调用创建一个新的进程。

相关知识

Linux系统中创建进程有很多函数可以使用,其中包括了系统调用也包括库函数。本关将介绍一个最常见的系统调用函数来创建进程,这就是使用fork函数来创建一个新进程。

当用户调用fork函数时,系统将会创建一个与当前进程相同的新进程。通常将原始进程称为父进程,而把新生成的进程称为子进程。子进程是父进程的一个拷贝,子进程获得同父进程相同的数据,但是同父进程使用不同的数据段和堆栈段。

在早期的系统中,创建进程比较简单。当调用fork时,内核会把所有的内部数据结构复制一份,复制进程的页表项,然后把父进程的地址空间中的内容也复制到子进程的地址空间中。但是从内核角度来说,这种复制方式是非常耗时的。

因此,在现代的系统中采取了更多的优化。现代的Linux系统采用了写时复制技术(Copy on Write),而不是一创建子进程就将所有的数据都复制一份。

Copy on Write(COW)的主要思路是:如果子进程/父进程只是读取数据,而不是对数据进行修改,那么复制所有的数据是不必要的。因此,子进程/父进程只要保存一个指向该数据的指针就可以了。当子进程/父进程要去修改数据时,那么再复制该部分数据即可。这样也不会影响到子父进程的执行。因此,在执行fork时,子进程首先只复制一个页表项,当子进程/父进程有写操作时,才会对所有的数据块进行复制操作。

[COW思路]

Linux系统中可以使用man命令来查询该函数的使用方法。具体的查询命令为: man 2 函数名

使用fork函数创建进程

fork函数的具体的说明如下:

  • 需要的头文件如下:
  • i. #include <unistd.h>
  • 函数格式如下: pid_t fork(void);
  • 函数返回值说明: 调用成功,fork函数两个值,分别是0和子进程ID号。当调用失败时,返回-1,并设置错误编号errno

注意:fork函数调用将执行两次返回,它将从父进程和子进程中分别返回。从父进程返回时的返回值为子进程的 PID,,而从子进程返回时的返回值为0,并且返回都将执行fork之后的语句。

案例演示1: 编写一个程序,使用fork函数创建一个新进程,并在子进程中打印出其进程ID和父进程ID,在父进程中返回进程ID。详细代码如下所示:

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <errno.h>

  6. int main()
  7. {
  8.    pid_t pid;
  9.    pid = fork();
  10.    if(pid == -1)
  11.    {
  12.        //创建进程失败
  13.        printf("创建进程失败(%s)!\n", strerror(errno));
  14.        return -1;
  15.    }
  16.    else if(pid == 0)
  17.    {
  18.        //子进程
  19.        printf("当前进程为子进程:pid(%d),ppid(%d)\n", getpid(), getppid());
  20.    }
  21.    else
  22.    {
  23.        //父进程
  24.        printf("当前进程为父进程:pid(%d),ppid(%d)\n", getpid(), getppid());
  25.    }
  26.    
  27.    //子进程和父进程分别会执行的内容
  28.    return 0;
  29. }

将以上代码保存为forkProcess.c文件,编译执行。可以看到每次执行forkProcess时,子进程和父进程都不是固定的执行顺序,因此由fork函数创建的子进程执行顺序是由操作系统调度器来选择执行的。因此,子进程和父进行在执行的时候顺序不固定。

编程要求

本关的编程任务是补全右侧代码片段中BeginEnd中间的代码,具体要求如下:

  • 补全createProcess函数,使用fork函数创建进程,并在子进程中输出"Children"字符串,在父进程中输出"Parent"字符串。(注意:不要在createProcess函数中使用exit函数或者return来退出程序)。

测试说明

本关的测试需要用户在右侧代码页中补全代码,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。

相关实践学习
CentOS 7迁移Anolis OS 7
龙蜥操作系统Anolis OS的体验。Anolis OS 7生态上和依赖管理上保持跟CentOS 7.x兼容,一键式迁移脚本centos2anolis.py。本文为您介绍如何通过AOMS迁移工具实现CentOS 7.x到Anolis OS 7的迁移。
目录
相关文章
|
14天前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
本文旨在探讨Linux操作系统中的进程管理机制,包括进程的创建、执行、调度和终止等环节。通过对Linux内核中相关模块的分析,揭示其高效的进程管理策略,为开发者提供优化程序性能和资源利用率的参考。
39 1
|
16天前
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
15天前
|
安全 Linux 数据安全/隐私保护
深入Linux操作系统:文件系统和权限管理
在数字世界的海洋中,操作系统是连接用户与硬件的桥梁,而Linux作为其中的佼佼者,其文件系统和权限管理则是这座桥梁上不可或缺的结构。本文将带你探索Linux的文件系统结构,理解文件权限的重要性,并通过实际案例揭示如何有效地管理和控制这些权限。我们将一起航行在Linux的命令行海洋中,解锁文件系统的奥秘,并学习如何保护你的数据免受不必要的访问。
|
15天前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
|
16天前
|
搜索推荐 Linux
深入理解Linux操作系统的启动过程
本文旨在揭示Linux操作系统从开机到完全启动的神秘面纱,通过逐步解析BIOS、引导加载程序、内核初始化等关键步骤,帮助读者建立对Linux启动流程的清晰认识。我们将探讨如何自定义和优化这一过程,以实现更高效、更稳定的系统运行。
|
14天前
|
存储 缓存 网络协议
Linux操作系统的内核优化与性能调优####
本文深入探讨了Linux操作系统内核的优化策略与性能调优方法,旨在为系统管理员和高级用户提供一套实用的指南。通过分析内核参数调整、文件系统选择、内存管理及网络配置等关键方面,本文揭示了如何有效提升Linux系统的稳定性和运行效率。不同于常规摘要仅概述内容的做法,本摘要直接指出文章的核心价值——提供具体可行的优化措施,助力读者实现系统性能的飞跃。 ####
|
16天前
|
存储 算法 调度
深入理解操作系统:进程调度的奥秘
在数字世界的心脏跳动着的是操作系统,它如同一个无形的指挥官,协调着每一个程序和进程。本文将揭开操作系统中进程调度的神秘面纱,带你领略时间片轮转、优先级调度等策略背后的智慧。从理论到实践,我们将一起探索如何通过代码示例来模拟简单的进程调度,从而更深刻地理解这一核心机制。准备好跟随我的步伐,一起走进操作系统的世界吧!
|
15天前
|
缓存 监控 网络协议
Linux操作系统的内核优化与实践####
本文旨在探讨Linux操作系统内核的优化策略与实际应用案例,深入分析内核参数调优、编译选项配置及实时性能监控的方法。通过具体实例讲解如何根据不同应用场景调整内核设置,以提升系统性能和稳定性,为系统管理员和技术爱好者提供实用的优化指南。 ####
|
16天前
|
算法 调度 开发者
深入理解操作系统:进程与线程的管理
在数字世界的复杂编织中,操作系统如同一位精明的指挥家,协调着每一个音符的奏响。本篇文章将带领读者穿越操作系统的幕后,探索进程与线程管理的奥秘。从进程的诞生到线程的舞蹈,我们将一起见证这场微观世界的华丽变奏。通过深入浅出的解释和生动的比喻,本文旨在揭示操作系统如何高效地处理多任务,确保系统的稳定性和效率。让我们一起跟随代码的步伐,走进操作系统的内心世界。
|
5月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能