进程概念
通俗来讲,进程是操作系统为了管理要运行程序的东西。
首先,我们要知道操作系统是干什么的。操作系统对下要管理好软硬件资源,对上提供一个良好的运行环境。
那么OS是如何管理的?首先,对于要管理的对象,建立一个struct结构体(操作系统使用C语言写的),这个结构体可以存储对象的各种属性;然后将各个结构体放到相应功能的数据结构中,由此,对对象的管理就变为了对数据结构的增删改查。
回到进程,当程序要运行时,OS会为程序创建对应的PCB结构体(存储了程序的各种信息),将PCB以及程序的数据和代码加载到内存,根据进程状态,放到对应的队列。例如,当前程序处于运行状态,就会放到运行队列。进程就是程序的代码和数据+对应的PCB数据结构组成的。
此外,不仅是进程,操作系统对其他对象进行管理也是一样,先为对象创建可以描述属性的结构体,然后放到一个数据结构组织起来。
如何查看进程
1.通过/proc系统文件查看,文件内有进程的各种属性
例如: ls /proc/1 查看PID为1的进程
2.通过ps指令
例如: ps axj | head -1 && ps axj | grep Proc | grep -v grep 查看进程名为Proc的信息
创建子进程——fork
fork是一个系统调用函数,用来创建子进程,通过多个执行流完成任务。子进程和父进程共用一份代码,子进程数据使用写时拷贝,即子进程数据在创建的时候和父进程相同,但是当要修改数据的时候,子进程数据会再复制一份数据。
函数无参,返回值pid_t是用有符号整形封装的。
函数返回值,如果创建成功,父进程就返回子进程的pid,子进程返回0,如果创建失败就返回-1
为什么父进程要返回子进程ID,子进程返回0?
因为父进程要对子进程操作时,如果没有返回值就找不到子进程;而子进程可以通过getpid()和getppid()获取自己进程ID和父进程ID。
为什么一个函数有两个返回值?
fork函数内部会创建并调度子进程,然后返回一个值,因为父子进程共享代码,return也会被执行两次,就会有两个返回值
进程状态
R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠
(interruptible sleep))。
当进程在等待资源时会进入,例如程序要获取输入,用户还未输入时
int main()
{
int n;
scanf("%d", &n);
return 0;
}
D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
当一个进程向磁盘写入数据时,在写入的这段时间内,进程就处于D状态,操作系统也无法杀掉该进程
T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
Z僵尸状态(zombie):如果子进程结束父进程还在运行,子进程不能直接销毁,对应的PCB还会存在,这是为了告知父进程其执行情况进程状态,此时子进程就处于僵尸状态。
僵尸进程也是内存泄漏,内存中不能有太多僵尸进程,只要出现操作系统可能就要崩溃了。
此外,如果父进程先结束了,子进程的PPID就会变为1,这样的进程称为孤儿进程
用top命令看到PID为1的
进程优先级
ps -l 查看进程信息
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
PRI :代表这个进程可被执行的优先级,其值越小越早被执行
NI :代表这个进程的nice值
进程优先级是nice值和priority的加和,可以通过修改nice值来控制优先级
如何修改呢?
命令行输入top,输入r,然后输入进程pid,输入nice值
当我们再次修改nice值时,新的PRI会从默认值80计算,nice值的范围是-20~19
环境变量
环境变量是一种用来存储系统配置信息的机制。环境变量包含了一些系统运行时需要的参数和信息,例如文件路径、用户权限、语言设定等等。
常见的环境变量
PATH : 指定命令的搜索路径
在shell输入命令,实际上就是运行一个进程,为什么我们自己写的进程就不可以直接使用呢?
因为PATH里有shell命令的路径,会自动在这些路径中查找,只要我们把自己的程序路径放到PATH中也可以直接使用,例如
HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
SHELL : 当前Shell,它的值通常是/bin/bash
环境变量相关指令
echo $name:查看环境变量name的内容
export name=123:设置一个 新的环境变量name并赋值
env:查看所有环境变量
unset name :删除环境变量
set 显示本地变量和环境变量
本地变量和内建命令
环境变量实际就是一种全局变量,它可以被子进程继承;本地变量只能在本进程使用
下面给出验证:
设置成bash的本地变量时,子进程不能获取;当设置为环境变量就可以了
那为什么echo就可以获取本地变量呢?echo难道不是bash的子进程吗?
是的,echo是bash的内建命令。例如pwd,cd等这些命令,都是内建命令。它们本质类似于bash自己定义的函数。试想,cd如果是子进程,那么改变的路径也是子进程的路径,bash本身的路径也没有变,所以这些命令只能写成内建命令。
进程获取环境变量——main函数传参/直接声明
main函数的前两个参数——命令行参数
argc表示接收命令行参数的个数,argv是存储命令的数组,每个命令都是一个字符串
ls -a -l 就是三个命令行参数,argv[0] = ls argv[1] = -a argv[2] = -l
main函数第三个参数
第三方变量environ获取
libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明