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

操作系统——进程管理

目录

  • 准备工作
    • 1. 编辑c语言源程序
    • 2. 编译c语言源程序
    • 3. 调试运行
      • 方式一:gdb ./test.c
      • 方式二:./test
  • gcc 编译器的安装
  • 一、关于进程的系统调用
  • 二、 探究内容
    • 1、进程的创建
      • 分析
      • 结论
      • 运行结果
    • 2、进程的同步
      • 代码执行流程
      • 关键特性
      • 结果
    • 3.进程的延迟
      • 分析
      • 结果
    • 4.进程执行另一程序
      • 结果
    • 5.编写一段程序
      • 结果
      • 原因分析
      • 总结

准备工作

1. 编辑c语言源程序

$vim   test.c~~~~ 

按键,进入编辑模式,程序输入完成后,按键,退出编辑模式。
按 : 键,进入命令行模式。所有需要在底部命令行执行的指令,都需要以:开头来触发。

  • :w 保存当前文件(write),但不退出vim。
  • :q (quit)不存盘并退出vim编辑,返回命令行方式。(若文件有未保存的修改,执行:q会报错)
  • :wq保存并退出,是最常用的命令。
  • :q!强制退出,不保存任何修改。

2. 编译c语言源程序

$gcc -o test -g test.c
没有错误提示,表示编译成功;否则返回vim中进行修改。
编译成功后,可通过 ./test 运行程序,或通过 gdb ./test 启动调试工具进行调试。

参数说明

  • gcc:GNU C 编译器,用于将 C 语言源代码编译为可执行程序
  • -o test:指定编译输出的可执行文件名为 test(如果不指定,默认输出文件名为 a.out
  • -g:在编译时添加调试信息,方便后续对程序进行调试(如设置断点、查看变量等)。
  • test.c:要编译的 C 语言源代码文件。

3. 调试运行

方式一:gdb ./test.c

$ gdb test
:
:<出现提示信息>
:

(gdb) 输入run ,程序即可运行,输出运行结果。
gdb方式运行结果1
gdb2

方式二:./test

通过 ./test 直接运行程序,得出结果

gcc 编译器的安装

ubuntu上没有装gcc编译器,需要自己安装。
安装命令如下:
sudo apt install gcc
由于上一次在安装了vim(shell编程(2)——基础知识结合小案例实现
),本次安装应该没有任何问题。
安装完成后,使用gcc --version命令查看,证明安装成功。
在这里插入图片描述
在这里插入图片描述

一、关于进程的系统调用

  1. 进程的创建 fork()
    格式:pid=fork()
    功能:创建一个新进程,新进程与父进程具有相同的代码,父子进程都从fork()之后的那条语句开始执行。
  • a)对于父进程,pid 的值>0;
  • b)对于子进程,pid的值=0;
  • c)创建失败,pid的值<0。

pid 是 Process ID(进程标识符) 的缩写,是操作系统为每个运行中的进程分配的唯一整数标识符,用于唯一标识一个进程。

  1. 进程的终止 exit()
    格式:exit(status)
    功能:终止当前进程的执行,status是一个整数,其值可以返回父进程。

  2. 进程的同步 wait()
    格式:wait()
    功能:使父进程进入睡眠状态,直到子进程终止后被唤醒,用于实现父子进程的同步。

  3. 进程的延迟 sleep()
    格式:sleep(n)
    功能:当前进程延迟n秒执行。

  4. 进程执行另一程序 execl()
    功能:在当前进程中执行另一个程序,替换原有进程的代码、数据等,实现进程功能

二、 探究内容

1、进程的创建

执行下面的程序,分析执行的结果。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>  // 包含fork函数的声明int  main(){  int i;printf("just 1 process.\n");i=fork();if (i==0)printf("I am child.\n");else if (i>0)printf("I am parent.\n");else printf("fork() failed.\n");printf("program end.\n");return 0;}

分析

创建子进程:执行 i = fork()
fork() 会创建一个与父进程几乎完全相同的子进程,父子进程从 fork() 之后的代码开始分别执行。
父进程中,fork() 返回子进程的 PID(大于 0),因此 i > 0。
子进程中,fork() 返回 0,因此 i == 0。
若创建失败(极少发生),fork() 返回负数,执行 fork() failed.

结论

  • fork() 调用后,系统中会出现两个独立的进程(父进程和子进程),且从 fork() 之后的代码开始并行执行。
  • 父子进程通过 fork() 的返回值区分身份(父进程得到子进程 PID,子进程得到 0)。
  • 父子进程的执行顺序由操作系统调度决定,因此分支代码的输出顺序可能不固定,但初始的 just 1 process. 只会输出一次(仅父进程在 fork() 前执行)。

运行结果

在这里插入图片描述
在这里插入图片描述

2、进程的同步

 #include <stdio.h>#include <stdlib.h>#include <unistd.h>#include<sys/wait.h>		//wait()
int main(){  int i;printf("just 1 process.\n");i=fork();if (i>0){	 printf("I am parent.\n");wait();}else{if (i==0){ printf("I am child.\n");exit(1);}}printf("program end.\n");}

代码执行流程

  • 初始阶段:
    程序启动后,只有父进程运行,执行 printf("just 1 process.\n"),输出:just 1 process.
  • 创建子进程:执行 i = fork()
    • 父进程中,fork() 返回子进程的 PID(i > 0)。
    • 子进程中,fork() 返回 0(i == 0)。
  • 父进程分支(i > 0):
    • 执行 printf("I am parent.\n"),输出:I am parent.
    • 调用 wait():父进程进入阻塞状态,等待子进程终止后再继续执行。
  • 子进程分支(i == 0):
    • 执行 printf("I am child.\n"),输出:I am child.
    • 调用 exit(1):子进程立即终止,退出状态码为 1(该状态码会被父进程的 wait() 获取,但代码中未显式处理)
  • 后续执行:
    子进程终止后,父进程的 wait() 被唤醒,继续执行后续代码。
    父进程执行最后一句 printf("program end.\n"),输出:program end.
    子进程因已调用 exit(1),不会执行最后一句 printf(直接终止)。

关键特性

  • 同步机制:wait() 确保父进程等待子进程执行完毕后再继续,避免父进程先于子进程结束。
  • 子进程终止:exit(1) 使子进程主动退出,且不再执行后续代码(因此子进程不会输出 program end.)。
  • 输出顺序固定:由于 wait() 的作用,父进程必须等待子进程输出I am child.并终止后,才会继续输出 program end.,因此输出顺序是确定的。

结果

  1. 使用wait()函数时,需要在开始加入#include<sys/wait.h>头文件,否则会发生以下报错。
    wait()缺头文件报错
    2.wait 函数的声明是 pid_t wait(int *stat_loc);,它需要一个指向 int 的指针作为参数,用于接收子进程的退出状态信息。如果不需要获取子进程的退出状态,可以传递 NULL。

wait() 函数需要一个参数(用于存储子进程的退出状态)
wait()缺参数
这里根据需要,向wait()函数传入NULL就行了,我并不关注子进程的退出状态。
在这里插入图片描述
在这里插入图片描述

3.进程的延迟

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>	//fork(),sleep()
int main(){int i,j,k;i=fork();if(i>0)for(j=1;j<=5;j++){sleep(1);printf("I am parent.\n");}elseif(i==0){for(k=1;k<=5;k++){sleep(1);printf("I am child.\n");}}return 0;}

分析

通过fork()系统调用创建一个子进程,父进程i > 0,执行一个循环,从 j=1到 j=5,每次循环休眠1秒后输出 I am parent.。子进程i == 0,执行另一个循环,从 k=1到 k=5,每次循环休眠1秒后输出 I am child.。父子进程并发执行各自的循环逻辑,输出顺序由操作系统调度决定,交替输出“父进程”和“子进程”的提示信息,最终各自完成 5 次输出后结束。

结果

在这里插入图片描述
在这里插入图片描述

4.进程执行另一程序

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>int main(){int i;char name[20];printf("Please input a directory name:\n");scanf("%s",name);i=fork();	//单独赋值,避免优先级问题if(i==-1){perror("fork failed");return 1;}else if(i==0){execl("/bin/ls","ls","-l",name,NULL);else{}
}

结果

在这里插入图片描述
在这里插入图片描述

5.编写一段程序

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

代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>int main() {// 创建第一个子进程pid_t pid1 = fork();if (pid1 == -1) {perror("fork failed");return 1;}if (pid1 == 0) {// 第一个子进程:输出 'b'printf("b");return 0; }// 父进程继续创建第二个子进程pid_t pid2 = fork();if (pid2 == -1) {perror("fork failed");return 1;}if (pid2 == 0) {// 第二个子进程:输出 'c'printf("c");return 0; }// 父进程:等待两个子进程结束后输出 'a'wait(NULL); // 等待第一个子进程wait(NULL); // 等待第二个子进程printf("a");return 0;
}

结果

在这里插入图片描述
在这里插入图片描述

原因分析

  1. 进程创建机制

    • 父进程首先通过 fork() 创建第一个子进程(输出 ‘b’),再创建第二个子进程(输出 ‘c’)。
    • fork() 后,子进程与父进程并发执行,操作系统的进程调度算法决定了它们的执行顺序(内核级调度,不受用户程序直接控制)。
  2. 输出顺序不确定性

    • 三个进程(父进程、子进程1、子进程2)的执行顺序由 CPU 调度决定。例如:
      • 可能子进程1先执行(输出 ‘b’),再子进程2(输出 ‘c’),最后父进程(输出 ‘a’),结果为 bca
      • 也可能子进程2先执行(输出 ‘c’),再子进程1(输出 ‘b’),最后父进程(输出 ‘a’),结果为 cba
  3. 父进程的等待逻辑

    • 代码中父进程通过 wait(NULL) 等待两个子进程结束后再输出 ‘a’,因此 ‘a’ 一定在最后输出(避免父进程先于子进程执行)。但两个子进程之间的输出顺序仍不确定。

总结

输出结果中 a 始终在最后,但 bc 的顺序不固定,这是因为 子进程与父进程的执行顺序由操作系统调度算法决定,属于正常的并发执行特性。若需固定顺序,需通过进程同步机制(如信号量、管道)额外控制。

http://www.dtcms.com/a/495534.html

相关文章:

  • 在docker运行ros及其可视化
  • Python使用 pandas操作Excel文件并新增列数据
  • 宝塔面板点击ssl证书报错:出错了,面板运行时发生错误!ModuleNotFoundError: No module named ‘OpenSSL‘
  • Django与Tornado框架深度对比:从MVCMTV到高并发架构设计
  • 湖南畅想网站建设大连品牌网站建设公司
  • S4和ECC或者不通CLIENT,不通HANA服务器互相取数
  • Linux中控制台初始化console_init函数的实现
  • pycharm 默认终端设置 cmd
  • JavaScript 加密工具 sojson.v5 全解析:原理、应用与实践
  • 【Python库包】ESMF 库包介绍及安装
  • HarmonyOS ArkUI框架自定义弹窗选型与开发实战
  • 智能体开发(2)智能数据处理Agent
  • Visual Studio在一个解决方案管理多项目属性
  • 网站图片防盗连怎么做韶关营销网站开发
  • 10.17 设置组件导航和页面路由
  • 福田做商城网站建设找哪家公司比较安全简约好看的网站模板免费下载
  • 【GD32F527_EVAL】USB 驱动移植 和 USB CDC Device 接入PC实验
  • 网站开发网站定制查看网站源代码建站可以
  • stm32_QT6怎么打包
  • c 做网站流程如何做做网站
  • 深度剖析大模型Function Calling:从原理到优化策略
  • SQL入门:表关联-从基础到优化实战
  • YOLOv3 技术总结
  • 为什么有些前端开发者能快速交付,有些还在纠结架构设计
  • Calibre(开源电子书管理软件) v8.13.0 官方便携版
  • wordpress数据库端口娄底seo排名
  • 途牛旅游网站建设方案临安区做网站的公司
  • 【原理扫描】SSL/TLS 服务器瞬时 Difie-Hellman 公共密钥过弱
  • Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
  • QML学习笔记(四十)QML的FileDialog和FolderDialog