进程的概念
程序
存放在磁盘上的指令和数据的有序结合(文件);
静态的。
进程
执行一个程序所分配的资源的总称;
进程是程序的一次执行过程;
动态的,包括创建、调度、执行和消亡。
进程类型
交互进程:在shell下启动。以在前台运行,也可以在后台运行
批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行
守护进程:和终端无关,一直在后台运行
进程常用命令
查看进程信息
ps 查看系统进程快照
top 查看进程动态信息
/proc 查看进程详细信息
ps 命令详细参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用
表头 | 含义 |
F | 进程标志,说明进程的权限,常见的标志有两个:
|
S | 进程状态。进程状态。常见的状态有以下几种:
|
UID | 运行此进程的用户的 ID; |
PID | 进程的 ID; |
PPID | 父进程的 ID; |
C | 该进程的 CPU 使用率,单位是百分比; |
PRI | 进程的优先级,数值越小,该进程的优先级越高,越早被 CPU 执行; |
NI | 进程的优先级,数值越小,该进程越早被执行; |
ADDR | 该进程在内存的哪个位置; |
SZ | 该进程占用多大内存; |
WCHAN | 该进程是否运行。"-"代表正在运行; |
TTY | 该进程由哪个终端产生; |
TIME | 该进程占用 CPU 的运算时间,注意不是系统时间; |
CMD | 产生此进程的命令 |
top 查看进程动态信息
shift +> 后翻页
shift +< 前翻页
top -p PID 查看某个进程
改变进程优先级
nice 按用户指定的优先级运行进程
nice [-n NI值] 命令
- NI 范围是 -20~19。数值越大优先级越低
- 普通用户调整 NI 值的范围是 0~19,而且只能调整自己的进程。
- 普通用户只能调高 NI 值,而不能降低。如原本 NI 值为 0,则只能调整为大于 0。
- 只有 root 用户才能设定进程 NI 值为负值,而且可以调整任何用户的进程。
renice 改变正在运行进程的优先级
renice [优先级] PID
jobs 查看后台进程
bg 将挂起的进程在后台运行
fg 把后台运行的进程放到前台运行
ctrl+z 把运行的前台进程转为后台并停止。
./test & 把test程序后台运行
子进程概念
子进程为由另外一个进程(对应称之为父进程)所创建的进程
子进程创建-fork
#include <unistd.h>
pid_t fork(void);
- 创建新的进程,失败时返回-1
- 成功时父进程返回子进程的进程号,子进程返回0
- 通过fork的返回值区分父进程和子进程
要点:
1.子进程只执行fork之后的代码
2.父子进程的执行顺序是操作系统决定的
3.子进程继承了父进程的内容
4.父子进程有独立的地址空间,互不影响
5.若父进程先结束
- 子进程成为孤儿进程,被init进程收养
- 子进程变成后台进程
6若子进程先结束
- 父进程如果没有及时回收,子进程变成僵尸进程
进程创建 – fork – 示例
#include <stdio.h>
#include <unistd.h>
int main(int argc,char **argv){
pid_t pid;
printf("before fork\n");
pid = fork();
if(pid>0){
printf("This is father process\n");
printf("pid=%d\n",(int)pid);
printf("father after fork\n");
while(1){
sleep(1);
printf("father sleep\n");
}
}else if(pid==0){
printf("This is child process\n");
printf("pid=%d\n",(int)pid);
printf("child after fork\n");
while(1){
sleep(1);
printf("child sleep\n");
}
}else if(pid<0){
perror("fork");
return 0;
}
// printf("pid=%d\n",(int)pid);
// printf("after fork\n");
}
进程结束 – exit/_exit
#include <stdlib.h>
#include <unistd.h>
void exit(int status);
void _exit(int status);
void _Exit(int status);
- 结束当前的进程并将status返回
- exit结束进程时会刷新(流)缓冲区
进程返回值和结束方式
子进程通过exit / _exit / return 返回某个值(0-255) 父进程调用wait(&status) 回收 WIFEXITED(status) 判断子进程是否正常结束
WEXITSTATUS(status) 获取子进程返回值
WIFSIGNALED(status) 判断子进程是否被信号结束
WTERMSIG(status) 获取结束子进程的信号类型
进程回收-wait
#include <sys/wait.h>
pid_t wait(int *status);
- 成功时返回回收的子进程的进程号;
- 失败时返回EOF 若子进程没有结束,父进程一直阻塞
- 若有多个子进程,哪个先结束就先回收
- status 指定保存子进程返回值和结束方式的地址
- status为NULL表示直接释放子进程PCB,不接收返回值
- 子进程结束时由父进程回收
- 孤儿进程由init进程回收
- 若没有及时回收会出现僵尸进程
进程回收-waitpid
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int option);
- 成功时返回回收的子进程的pid或0;
- 失败时返回EOF
- pid可用于指定回收哪个子进程或任意子进程
- status指定用于保存子进程返回值和结束方式的地址
- option指定回收方式,0 或 WNOHANG
进程回收 – waitpid – 示例
waitpid(pid, &status, 0);
waitpid(pid, &status, WNOHANG);
waitpid(-1, &status, 0);
waitpid(-1, &status, WNOHANG);
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char** argv){
pid_t pid;
pid_t rpid;
pid = fork();
int status;
if(pid<0){
perror("fork");
return 0;
}
else if(pid == 0){
sleep(10);
printf("child will exit\n");
exit(2);
}else if(pid >0){
//rpid = wait(&status);
sleep(20);
waitpid(-1,&status,WNOHANG);
printf("Get child status=%x\n",WEXITSTATUS(status));
}
while(1){
sleep(1);
}
}