进程
(硬件中断技术的出现,进而软件上有了分时系统,时间片轮转)
进程:从用户角度看,进程是程序的一次动态执行过程
从操作系统的角度看:
(1).进程是操作系统分配内存,CPU时间片等系统资源的基本单位
(2).每个进程有自己独立的地址空间和进程状态
(3).进程是分配资源的最小单位
程序:为了执行特定任务的一系列指令的有序集合
进程的所有过程都是围绕下图进行:
进程是程序的一次执行过程,需要保存进程的现场信息,这些信息需要一个数据结构来保存,在c语言中用结构体,我们将这个结构称为PCB(process control block)
struct PCB{
pc; 下一条指令的地址
esp; 栈顶指针
ebp; 基址
};
PCB是操作系统感知一个进程存在的重要数据结构
程序:代码段 + 数据段
进程:代码段 + 数据段 + 堆栈 + PCB
PCB将代码和数据有效的粘合在一起
进程和程序的区别:
1.进程是动态的,程序是静态的
2.进程是短暂的,程序是永久的
3.进程有PCB
4.一个进程只能对应一个程序,一个程序可以对应多个进程
awk ‘printf(“%s\n”,$2)’
状态变迁:
三态
linux七态
ps 查看进程状态
ps aux
ps -ef
linux 对应的PCB数据结构:task_struct
○ 进程标识符
○ 进程状态
○ 进程优先级
○ 各种时间信息
○ 进程间通信
○ 内存使用情况
○ 寄存器
内存使用情况
进程标识符
操作系统会给每个进程分配一个独一无二的编号
编号的范围【2-cat /proc/sys/kernel/pid_max】
0 表示内核进程
0号进程只启动1号进程。init 0
swap 分区
创建进程的一般过程:
1.给新建的进程分配一个进程标识符
2.在内核中创建PCB
3.复制父进程的环境
4.给子进程分配资源,栈,堆,代码,数据等
5.复制父进程的地址空间内容到子进程的地址空间
6.将新进程置为就绪态放入就绪队列
pid_t fork(void);
fork一次调用,返回两个pid
在父进程中返回子进程ID,子进程返回0(返回先后没有规定)
获得进程ID:getpid(void);
获得父进程ID:getppid(void);
kill pid:杀死某个进程
kill -9 pid:必定杀死该进程(僵尸进程无法杀死)
fork注意点:
1.fork之后,父子进程交替运行
2.如果父进程死亡,子进程还活着,子进程就是孤儿进程,每个子进程都有父进程,因此孤儿进程会托管给1号进程。(1号进程被称为系统孤儿院)
3.如果父进程活着,子进程死了,子进程就是僵尸进程,僵尸进程是会占用系统资源(僵尸进程是有害的)。
错误处理:
所有错误返回-1代表失败
定义一个全局变量 error,保存返回值,通过strerror得到对应的描述
进程被虚拟成文件,/proc/pid/
ps -el | grep a.out | grep -v grep
进程优先级
nice -n 优先级 进程:修改优先级
renice 优先级 -p 进程id
top 查看
Shift < :下一屏幕
Shift > :上一屏幕
写时拷贝:
没有必要全部拷贝一份,父子进程什么时候修改,什么时候拷贝一份出来。称之为写时拷贝。
第二个创建子进程的函数:pid_t vfork();
1.父进程阻塞,直到子进程运行完毕
2.就算写时,也不拷贝
3.必须使用exit或者exec
4.每个系统对vfork的实现或多或少都有问题,不要使用。
销毁进程:
1.释放资源。内存,文件等等
2.记账信息
3.将进程设置为僵尸状态
4.转存储调度,将CPU让给需要使用的过程
退出进程的方法:
正常退出:
1.main函数退出
2.exit (执行三步)
1)执行退出处理函数
2)刷新缓存
3)调用_exit
异常退出:
1.ctrl+c
2.abort
3.kill
等待进程:
pid_t wait(int *status);//专门回收僵尸进程
//阻塞,直到有子进程退出才返回,status参数会得到子进程是如何死亡的
//返回值是子进程id,出错返回-1
$?:打印上一条退出程序的退出码
WIFEXITED(status) //如果正常退出,返回真
WEXITSTATUS(status) //如果正常退出,得到退出码
WIFSIGNALED(status)//如果被信号打断,返回真
WTERMSIGN(status)//如果正常退出,得到打断信号的值
pid_t waitpid(pid_t pid, int *status, int options);
pid>0:等待进程id等于pid的子进程死亡
pid=0:调用者进程组所在进程组的任何一个子进程死亡
pid=-1:等待任何一个子进程死亡
pid<-1:|pid|进程组的任何一个子进程死亡
替换进程空间
int execvp(const char *file, char *const argv[]);
const char *file:可执行程序名
char *const argv[]:main函数参数
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg,
..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
v:vector
l:
p:path
e:
环境变量:
grep -A2 -B2 bash:打印bash的前后两行
定义变量:name=value 等号两侧不能有空格
删除变量 :unset name
每个进程的变量只能在当前进程使用,环境变量可以在当前进程和子进程中使用,如果需要在子进程中使用父进程的变量。
需要使用export name:(将本地变量转为环境变量)
1.系统有那些环境变量
env:查看当前系统的环境变量
2.将自己定义的环境变量盛放在哪?终端打开就存在该环境变量
登录shell之前会执行 ~/.bash_profile 文件(本用户的配置)
/etc/profile 文件 整个系统所有用户的配置
程序中如何操作环境变量:
设置环境变量:int putenv(const char* str); str的格式“name=value”
取得一个环境变量的值:getenv(const char *name);
获得所有的环境变量的值:用main函数的第三个参数循环打印
int main(int argc,char argv[],char envp[i]);