进程的概念
进程和程序的区别
程序
- 存放在磁盘上的指令和数据的有序集合(文件)
- 静态的
进程
- 执行一个程序所分配的资源的总称
- 进程是程序的一次执行过程
- 动态的,包括创建、调度、执行和消亡
进程的内容(面试重点)
-
**BSS段:**BSS段通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。
-
**数据段:**数据段通常是指用来存放程序中已初始化的全局变量的一块内存区域。
-
**代码段:**代码段通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
-
**堆(heap):**堆是用于存放进程运行中被动态分配的内存段,当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
-
**栈(stack):**栈又称堆栈, 是用户存放程序临时创建的局部变量,(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进后出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
进程类型
- 交互进程:在shell下启动。以在前台运行,也可以在后台运行
- 批处理进程:和在终端无关,被提交到一个作业队列中以便顺序执行
- 守护进程:和终端无关,一直在后台运行
进程状态
- 运行态:进程正在运行,或者准备运行
- 等待态:进程在等待一个事件的发生或某种系统资源
可中断
不可中断
- 停止态:进程被中止,收到信号后可继续运行
- 死亡态:已终止的进程,但pcb没有被释放
僵尸态是linux特有的状态
进程基础命令
查看进程信息
- ps 查看系统进程快照
- top 查看进程动态信息 (shift + >向上翻页)
- /proc 查看进程详细信息
ps命令
ps 命令详细参数:
-e:显示所有进程
-l:长格式显示更加详细的信息
-f 全部列出,通常和其他选项联用
常用下面语法来查看一个进程:
ps -elf|grep 进程名字
表头 | 含义 |
---|---|
F | 进程标志,说明进程的权限,常见的标志有两个: 1:进程可以被复制,但是不能被执行; 4:进程使用超级用户权限; |
S | 进程状态。进程状态。常见的状态有以下几种: 1. -D:不可被唤醒的睡眠状态,通常用于 I/O 情况。 2. -R:该进程正在运行。 3. -S:该进程处于睡眠状态,可被唤醒。 4. -T:停止状态,可能是在后台暂停或进程处于除错状态。 5. -W:内存交互状态(从 2.6 内核开始无效)。 6. -X:死掉的进程(应该不会出现)。 7. -Z:僵尸进程。进程已经中止,但是部分程序还在内存当中。 8. -<:高优先级(以下状态在 BSD 格式中出现)。 9. -N:低优先级。 10. -L:被锁入内存。 11. -s:包含子进程。 12. -l:多线程(小写 L)。 13. -+:位于后台。 |
UID | 运行此进程的用户的 ID; |
PID | 进程的 ID; |
PPID | 父进程的 ID; |
C | 该进程的 CPU 使用率,单位是百分比; |
PRI | 进程的优先级,数值越小,该进程的优先级越高,越早被 CPU 执行; |
NI | 进程的优先级,数值越小,该进程越早被执行; |
ADDR | 该进程在内存的哪个位置; |
SZ | 该进程占用多大内存; |
WCHAN | 该进程是否运行。"-"代表正在运行; |
TTY | 该进程由哪个终端产生; |
TIME | 该进程占用 CPU 的运算时间,注意不是系统时间; |
CMD | 产生此进程的命令名; |
top命令
top 查看进程动态信息
shift +> 后翻页
shift +< 前翻页
查看某个进程:
top -p PID
改变进程优先级
nice命令
- nice 按用户指定的优先级运行进程
nice [-n NI值]
NI 范围是 -20~19。数值越大优先级越低
普通用户调整 NI 值的范围是 0~19,而且只能调整自己的进程。
普通用户只能调高 NI 值,而不能降低。如原本 NI 值为 0,则只能调整为大于 0。
只有 root 用户才能设定进程 NI 值为负值,而且可以调整任何用户的进程。
renice命令
- renice 改变正在运行进程的优先级
renice [优先级] PID
进程前后台
jobs命令
jobs
查看后台进程
bg命令
bg [进程号]
将挂起的进程在后台运行
fg命令
fg [进程号]
把后台运行的进程放到前台运行
ctrl+z
把运行的前台进程转为后台并停止。
./test &
把test程序后台运行
写一个循环文件test.c测试
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv){
while(1){
sleep(1);
}
return 0;
}
子进程(重点)
- 子进程为由另外一个进程(对应称之为父进程)所创建的进程
- linux除了0号进程都是子进程
子进程创建-fork命令
#include <unistd.h>
pid_t fork(void);
- 创建新的进程,失败时返回-1
- 成功时父进程返回子进程的进程号,子进程返回0
- 通过fork的返回值区分父进程和子进程
示例:
输出子进程和父进程的进程号
pid_t pid;
if ((pid = fork()) < 0) {
perror(“fork”);
return -1;
}
else if (pid == 0) {
printf(“child process : my pid is %d\n”, getpid());
}
else {
printf(“parent process : my pid is %d\n”, getpid());
}
父子进程的关系
- 子进程继承了父进程的内容
- 父子进程有独立的地址空间,互不影响
- 若父进程先结束
子进程成为孤儿进程,被init进程收养
子进程变成后台进程
- 若子进程先结束
父进程如果没有及时回收,子进程变成僵尸进程
- 子进程只执行fork之后的代码
- for循环父子进程都会进行执行
- 父子进程谁先执行没有规律,由操作系统决定
进程结束-exit/_exit命令
#include <stdlib.h>
#include <unistd.h>
void exit(int status);
void _exit(int status);
void _Exit(int status);
- 结束当前的进程并将status返回
- exit结束进程时会刷新(流)缓冲区,_exit不会
- main函数结束时会隐式地调用exit函数,普通函数return是返回上一级
示例:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
printf(“this process will exit”);
exit(0);
printf(“never be displayed”);
}
输出:this process will be exit 返回值为0
进程回收-wait/waitpid命令
- 子进程结束时由父进程回收
- 孤儿进程由init进程回收
- 若没有及时回收会出现僵尸进程
wait命令
#include <sys/wait.h>
pid_t wait(int *status);
- 成功时返回回收的子进程的进程号;失败时返回EOF
- 若子进程没有结束,父进程一直阻塞
- 若有多个子进程,哪个先结束就先回收
- status 指定保存子进程返回值和结束方式的地址
- status为NULL表示直接释放子进程PCB,不接收返回值
进程返回值和结束方式(status的宏)
子进程通过exit / _exit / return 返回某个值(0-255)
父进程调用wait(&status) 回收
WIFEXITED(status) | 判断子进程是否正常结束 |
---|---|
WEXITSTATUS(status) | 获取子进程返回值 |
WIFSIGNALED(status) | 判断子进程是否被信号结束 |
WTERMSIG(status) | 获取结束子进程的信号类型 |
示例:
输出子进程的返回值
int status;
pid_t pid;
if ((pid = fork()) < 0) {
perror(“fork”); exit(-1);
}
else if (pid == 0) {
sleep(1); exit(2);
}
else {
wait(&status); printf(“%d\n”, WEXITSTATUS(status));
}
waitpid命令
参数比wait多了两个
wait(wait_stat) 等价于waitpid(-1,wait_stat,0)
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *status, int option);
- 成功时返回回收的子进程的pid或0;失败时返回EOF
- pid可用于指定回收哪个子进程或任意子进程
- status指定用于保存子进程返回值和结束方式的地址
- option指定回收方式,0 或 WNOHANG(不等待子进程结束)
pid参数:
pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。
options参数:
options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用
WNOHANG :若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0
少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。
options参数:
options提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用
WNOHANG :若由pid指定的子进程未发生状态改变(没有结束),则waitpid()不阻塞,立即返回0
WUNTRACED: 返回终止子进程信息和因信号停止的子进程信息