系统编程之进程管理

一、引言 进程是操作系统中的重要概念,是对执行一定功能的程序的过程的抽象。这篇文章将简要说明进程的相关知识。介绍进程管理相关的函数,并通过这些函数实现重定向和进程间通信等功能。 二、进程简介 1. 程序执行原理 程序在编译后以二进制方式存在于外存上,执行的时候被操作系统载入内存。以 Linux 系统上的 C 语言编译出来的程序为例,载入的过程简单来说就是把编译完成的 ELF (Executable and Linkable Format 可执行与可链接格式) 文件的几个段的内容读取到内存指定位置,然后初始化寄存器的内容,将指令寄存器(比如cs:ip)指向程序入口,再初始化一些进程相关内容就完成了。 在某一次时钟中断发生的时候,进程主动陷入内核态,进行进程切换的系统调用,CPU 将切换到另一个进程工作。总而言之,整个计算机从开机到关机,就是一个不断创建、切换、终止进程的过程。 2. 进程概念的用途 早期的计算机一次只能执行一个程序,这种程序完全控制系统,并且访问所有系统资源。相比之下,现代计算机系统允许“同时”加载多个应用程序到内存,以便并发(轮流)执行。 这种改进要求对各种程序提供更严的控制和更好的划分。这些需求导致了进程概念的诞生。 进程是现代分时操作系统的工作单元,是操作系统向运行中的程序进行资源分配的单位。进程包括程序代码(文本),当前活动(程序计数器,寄存器的值),堆栈,数据端,堆。 需要注意区分程序和进程的概念。程序是被动实体,如存储在磁盘上的可执行文件;进程是活动实体,具有一个程序计数器用于表示下个执行命令和一组相关资源。 当一个可执行文件被加载到内存时,这个程序就成为进程。 两个进程可以与同一程序相关联,但当作两个单独的执行序列,虽然文本段相同,但是数据、堆、堆栈不同。 三. 进程管理 接下来介绍使用操作系统 API 进行进程管理的方法。 1. 使用 fork 创建新进程 #include <unistd.h> pid_t fork(); fork 无参数,返回一个用于指示子进程的 pid(对于子进程,返回值为 0)。其作用是创建一个子进程,共享父进程所有内容,并且这个子进程会接着 fork 下面的代码继续执行。fork有以下两种用法: 一个父进程希望复制自己,使父进程和子进程同时执行不同的代码段。 一个进程要执行一个不同的程序。在这种情况下,子进程从fork返回后立即调用exec。 如果在调用 fork 后子进程先于父进程结束,则子进程就会变为僵尸进程,虽然结束,却依然占据了进程表中的一个位置。为了避免这种情况,需要调用 wait 或 waitpid 来使父进程等待子进程结束,并释放子进程的信息。 #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid,int *status,int options); 下面将以一个程序作为例子。该程序由父进程创建两个子进程,父进程打印字符 B ,两个子进程分别打印 A 和 C ,并且要使最终的输出为 ABC 。...

十月 31, 2022 · 4 分钟 · 651 字 · Wokron

系统编程之 Shell 编程

一、前言 本文将简单探索shell脚本编程,介绍shell的基本语法。 二、shell简介 shell是一个命令解释器,可以用来启动、停止、编写程序;是用户和UNIX/Linux操作系统内核程序间的一个接口。 而shell编程则是将linux命令与shell的各种流程控制和条件判断来组合成命令与变量,形成可以进行自动处理的脚本程序。 三、前期准备 创建脚本 shell脚本是一个文本文件,可用文本编辑器如vi、vim编辑保存。创建shell脚本只需按照创建文本文件的方式创建。如 vi c1.sh vim c2.sh > c3.sh shell脚本一般以.sh为后缀,但没有后缀依旧可以执行。 创建的shell脚本,一定要在开头第一行加上如下语句: #!/bin/bash 这一行将指明该脚本执行所需要的命令解释器。 执行脚本 shell脚本的执行方法有 sh <scriptname> bash <scriptname> 或者使用chmod命令修改脚本为可执行,再直接使用 ./<scriptname> 运行。 四、基本语法 变量 shell中的变量分为环境变量、用户定义变量、内部变量。 其中环境变量是操作系统的一部分,但可以利用shell脚本进行修改;用户变量即在脚本中声明的变量;而内部变量则用来指示脚本运行中出现的一些变量。 声明 只有用户变量可以声明。和其他语言一样,使用等号进行声明。但要注意的是,shell脚本是弱类型的,因此变量名前不需要加上类型名。 var=hello_world 注意shell对空格敏感,声明时等号两边不能有空格 另外可以在变量名前添加 readonly关键字设为只读 readonly constVar shell中声明数组同样直接写出数组名称 arr[0]=1 arr[1]=5 arr[10]=20 未赋值的部分默认为NULL。 注意 ubuntu 默认使用 dash 而非 bash shell。dash 并不支持数组。要使用数组可以用bash运行脚本,即运行命令 bash <scriptname> 赋值 shell变量有类似左值右值的区别。在用其他变量进行赋值时,需要对变量使用${ } 进行取值。 var1=hi var2=${var1} 引号 shell脚本是为了自动化处理命令而设计的。因此语法中有很大一部分关注于字符串和命令的相关操作。在变量上体现在,shell中所有变量默认以字符串形式存在。 并且,为了满足命令处理的需要,shell设计出了引号变量值。 shell中的引号包括单引号、双引号和倒引号。 单引号中的字符均作为普通字符出现。(可以包括空格) var1=hello_world # var2=hello world # 不合法 var3='hello world' 双引号中的字符大部分作为普通字符对待。除了$\’和双引号,这些变量依旧用于对字符串内容进行变量替换。...

十月 8, 2022 · 2 分钟 · 321 字 · Wokron

系统编程之命令行编译

一、前言 本文将简单介绍在Linux系统下的命令行编译流程。介绍gcc、gdb、make等工具的简单使用。 二、GCC 基本操作 编译选项 无选项编译链接 用法:gcc test.c 作用:将 test.c 预处理、编译、汇编并链接形成可执行文件。这里未指定输出文件,默认输出为 a.out。 选项 -o 用法:gcc test.c -o test 作用:将 test.c 预处理、编译、汇编并链接形成可执行文件 test。-o 选项用来指定输出文件的文件名。 选项 -E 用法:gcc -E test.c -o test.i 作用:将 test.c 预处理输出 test.i 文件。 选项 -S 用法:gcc -S test.i 作用:将预处理输出文件 test.i 编译成 test.s 文件。 选项 -c 用法:gcc -c test.s 作用:将汇编语言文件 test.s 汇编成目标代码 test.o 文件。 无选项链接 用法:gcc test.o -o test 作用:将目标代码文件 test.o 链接成最终可执行文件 test。 选项 -O 用法:gcc -O1 test.c -o test 作用:使用编译优化级别 1 编译程序。级别为 1~3,级别越大优化效果越好,但编译时间越长。 官方文档:GCC, the GNU Compiler Collection...

九月 12, 2022 · 3 分钟 · 589 字 · Wokron