以下内容源于网络资源的学习与整理,如有侵权请告知删除。
一、进程的概述
进程,是指一个具有独立功能的程序关于某个数据集合的一次可以并发执行的运行活动,是处于活跃状态的计算机程序,是系统进行资源分配和调度的基本单位。进程是一个程序的一次运行过程,同时也是资源分配的最小单位。程序是静态的,是一些保存在硬盘上的命令的有序集合。进程是动态的,是程序执行的过程。包括创建、调度和消亡的整个过程。
二、程序的开始与结束
1、main函数由谁调用
(1)编译链接时的引导代码
操作系统下的应用程序,在main函数执行前,需要先执行一段引导代码(为了构建C语言环境等目的)。我们编写代码时不用考虑引导代码,因为它是编译器自带的。链接时,链接器将编译器中自带的引导代码与应用程序一起构成最终的可执行程序。
(2)运行时的加载器
加载器是操作系统中的一个程序,当执行一个程序时(比如./a.out,或者用exec族函数来运行某个程序),加载器负责将程序加载到内存中。
2、程序如何结束
(1)正常终止:return、exit、_exit。
(2)非正常终止:自己或他人发信号(比如ctrl c 终止正在运行的程序),终止进程。
3、atexit()函数:注册进程终止处理函数
所需的头文件 #include <stdlib.h> 函数原型 int atexit(void (*function)(void)); 返回值 成功则返回0,失败则返回非零值。 (1)所谓进程终止处理函数,即进程终止前所要做的处理。
(2)使用atexit()函数注册多个进程终止处理函数,先注册的后执行。
(3)return、exit终止进程时,会执行进程终止处理函数;_exit不会执行。
(4)代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h>void func1(void) {printf("func1\n"); }void func2(void) {printf("func2\n"); }int main(void) {printf("hello world.\n");// 当进程被正常终止时,系统会自动调用这里注册的func1执行atexit(func2);atexit(func1);printf("my name is lilei hanmeimei\n");//return 0;//exit(0);_exit(0); }
三、进程的诞生与消亡
1、进程的诞生
(1)进程1从何而来?
进程0,是操作系统在启动过程中,由内核一点点构建起来。内核态下的进程1,是由进程0利用内核内部的“fork”创建出来,然后才转变为用户态下的进程1。
(2)其他进程从何而来?
其他进程都是由进程1直接或者间接使用fork()函数(或者vfork()函数)创建出来的。
2、进程的终止
(1)终止的方式
正常终止和异常终止。
(2)终止时资源回收问题
进程在运行时需要占用系统资源,比如内存和IO。进程终止时,操作系统会自动回收该进程涉及到的所有资源。比如malloc申请的内存没有free、open打开的文件没有close时,进程终止时将会释放内存与关闭文件。
操作系统只回收该进程工作时所占用的内存和IO,没有回收该进程本身占用的内存(8KB,主要是task_struct和栈内存)。这部分的内存需要该进程的父进程来回收。
(3)僵尸进程
如果子进程已经结束,父进程尚未回收子进程本身所占用的内存,则称子进程为僵尸进程。
父进程可以使用wait()函数,显式地回收僵尸进程的内存资源并且获取子进程退出状态;或者父进程结束时也会回收僵尸进程的内存资源。这样设计,可以防止父进程忘记显式调用wait()函数来回收子进程从而造成内存泄漏。
(4)孤儿进程
如果父进程先于子进程结束,则子进程成为一个孤儿进程。
inux系统规定,所有的孤儿进程都自动成为进程1(即init进程)的子进程。
四、进程状态与转换
1、进程的5种状态
(1)就绪态:这个进程当前所有运行条件就绪,只要得到CPU时间就能直接运行。
(2)运行态:就绪态时得到了CPU就进入运行态开始运行。
(3)僵尸态:进程已经结束但是父进程还没来得及回收。
(4)等待态:进程在等待某种条件,条件成熟后可进入就绪态。
(5)暂停态:暂停并不是进程的终止,只是被信号暂停了,可以恢复。
2、各种状态之间的转换
五、进程环境
1、环境变量
(1)环境变量的含义
环境变量是指进程运行的环境中的变量。当前进程的环境变量与系统环境变量可以使用export命令查看系统环境变量。
root@ubuntu:/home/xjh/iot/tmp# export declare -x CLUTTER_IM_MODULE="xim" declare -x COLORTERM="gnome-terminal" declare -x COMPIZ_CONFIG_PROFILE="ubuntu" declare -x DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-Gjr7Cf2p8H" declare -x DEFAULTS_PATH="/usr/share/gconf/ubuntu.default.path" declare -x DESKTOP_SESSION="ubuntu" declare -x DISPLAY=":0" declare -x GDMSESSION="ubuntu" declare -x GDM_LANG="en" declare -x GNOME_DESKTOP_SESSION_ID="this-is-deprecated" declare -x GNOME_KEYRING_CONTROL="/run/user/1000/keyring-qpyvSE" declare -x GNOME_KEYRING_PID="2007" //省略
(2)进程环境表
每个进程中都有一份所有环境变量构成的表格,此表格叫做进程环境表。它是一个字符串数组,当前进程可以直接使用这些环境变量。
我们在编程时,可以无条件地直接使用系统中的环境变量。一旦程序中用到环境变量,则程序就与具体操作系统的环境有关了。比如在编程中使用environ这个全局变量:
#include <stdio.h> int main(void) {extern char **environ; // 声明就能用,不用定义int i = 0;while (NULL != environ[i]){printf("%s\n", environ[i]);i++;}return 0;}
(3)getenv()函数、setenv函数
getenv()函数,用来获取指定环境变量函数getenv。
setenv函数,用来设置环境变量。注意,只能设置或删除当前进程的环境变量,而不是操作系统的环境变量。
所需头文件 #include <stdlib.h> 函数原型
char *getenv(const char *name); 返回值 成功则返回指向环境变量的指针。
所需头文件 #include <stdlib.h> 函数原型 int setenv(const char *name, const char *value, int overwrite); 返回值 成功则返回0,失败返回-1。 2、进程运行的虚拟地址空间
(1)虚拟地址空间的概念
操作系统中,每个进程之间是彼此独立的,都在独立的地址空间中运行。对于32位系统,操作系统为每个进程分配了4GB的虚拟地址空间,一般0~1G为OS,1~4G为应用。每个进程所占的物理内存其实并不多,所以我们可以给每个进程分配一段物理内存空间。这其中涉及到虚拟地址到物理地址的映射问题。
(2)虚拟地址空间的意义
进程隔离,提供多进程同时运行。