一、 程序、进程和线程的基本概念
程序
- 程序就是一个文件,只占用磁盘的空间,是静态概念。
进程
- 进程不会占用磁盘空间,系统会给进程分配cpu和内存。
- 每个进程对应一个虚拟地址空间
- 进程是并发执行的程序在执行过程中分配和管理资源的基本单位,是动态概念。
线程
- 线程是轻量级的进程,在Linux环境下线程的本质仍是进程。
- 线程是操作系统调度执行的最小单位。
- 多个子线程和主线程共用同一个虚拟地址空间
- 线程和进程一样都会争抢cpu资源
并行和并发
- 并行:多个人在同一个时间点干同一件事。
- 并发:同一个时间段处理若干个工作。
通俗点讲:并行是,我和你在同一个时间点都在跑步。并发是我在游泳的时候你可以看比赛。
二、 CPU时间片和进程控制块(PCB)
- cpu时间片
- 进程控制块(PCB)
- 进程id。系统中每个进程有唯一的id,在C语言中用pid_t类型表示,即非负整数。
- 进程的状态。有就绪、运行、挂起、停止等状态。
- 进程切换时需要保存和恢复的一些CPU寄存器。
- 描述虚拟地址空间的信息。
- 描述控制终端的信息。
- 当前工作目录。
- umask掩码。
- 文件描述符表,包含很多指向filed结构体的指针。
- 和信号相关的信息。
- 用户id和组id。
- 会话和进程组
- 进程可以使用的资源上限。
时间片即cpu分配给各个进程运行的时间,每个进程被分配一个时间段,称作时间片,使各个进程从表面上看是同时进行的。
每个时间片都是有限的,如果时间片结束时进程还在运行,进程将会被中断挂起等待下一个时间片,cpu则会被分配给另一个进程,如果在时间片结束前阻塞或结束,则cpu立即分配给另一个进程,这个行为称作时间片轮转。
Linux内核的进程控制块是task_struct结构体。结构体中包含如下信息:
三、 进程的创建
- 创建进程
- 结束进程
- 命令
- 查看进程
- 杀死进程
- 父子进程的异同点
- 相同点
- 子进程刚被创建出来,未进行任何操作时,父子进程之间共享文件描述符表。
- 子进程刚被创建出来,未进行任何操作时,父子进程之间共享用户区数据。
- 不同点
- fork()函数的返回值不同。
- 进程ID不同。
- 信号集不同。
1 //函数及头文件
2 #include <sys/types.h>
3 #include <unistd.h>
4 pid_t fork(void);
5
6 返回值类型是pid_t
7 成功则返回两个值
8 >0:父进程ID
9 ==0:子进程ID
1 // exit -> c库函数
2 #include <stdlib.h>
3 void exit(int status);
4
5 // _exit() -> linux系统函数
6 #include <unistd.h>
7 void _exit(int status);
8
9 state是返回值,返回给父进程
1 ps aux/ajx
2 a: 显示当前终端下的所有的程序, 包括所有的用户
3 u: 显示用户信息
4 x: 打印和tty终端先关的信息
5 j: 显示更多的用户信息
//查看信号(前面是数值,后面是宏值)
1 kill -l(注意是字母,不是数字)
2 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
3 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
4 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
5 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT
6 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
7 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU
8 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
9 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN
10 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4
11 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
12 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12
13 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14
14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10
15 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6
16 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
17 63) SIGRTMAX-1 64) SIGRTMAX
//杀死进程
(1)kill -SIGKILL 进程ID(PID)
(2)kill -9 进程ID(PID)
四、 进程的回收
- 僵尸进程
- 孤儿进程
- 进程回收函数
子进程结束,但父进程还在运行,并且没有回收子进程的PCB(进程控制块)。这时子进程不占用内存,只有一个PCB,没有用户区数据,不会被系统调度,因此不能称作一个存活的进程。
父进程结束,但子进程还在运行。此时子进程会被初始进程领养并释放。
1 #include <sys/types.h>
2 #include <sys/wait.h>
3 pid_t wait(int *wstatus);
5 返回值:
6 >0: 则是被回收进程的ID
7 ==-1: 函数调用失败
参数:
是传入参数,记录进程退出状态
8 pid_t waitpid(pid_t pid, int *wstatus, int options);
5 返回值:
6 >0: 则是被回收进程的ID
7 ==-1: 函数调用失败
参数:
pid: 要回收的进程的进程ID
<-1: 回收进程组ID为pid绝对值的进程组。
=-1: 回收所有子进程。
==0: 回收当前进程的所有子进程,包括在别的进程组内的
>0: 则是被回收进程的ID
*wstatus:是传入参数,记录进程退出状态
options:
WNOHANG: 设置为非阻塞
WUNTRACED:
WCONTINUED:
五、 exec函数族
- 介绍
exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。
函数族的函数执行成功后不会返回,只有调用失败了,它们会返回-1,从原程序的调用点接着往下执行。
如果调用成功调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只有进程ID等一些表面上的信息仍保持原样。
1 #include <unistd.h>
1 extern char **environ;
2 int execl( const char *path, const char *arg, ...);
3 参数:
5 path: 可执行文件的路径
6 arg: 传给可执行文件的参数
7 ...: 代表这个函数是个可变参数,参数数量不定,例如printf
8
9 int execlp( const char *file, const char *arg, ...);
10 参数:
11 file: 可执行程序的名字,但必须在环境变量path中
12 arg: 传给可执行文件的参数
13
14 int execle( const char *path, const char *arg , ..., char * const envp[]);
15 int execv( const char *path, char *const argv[]);
16 int execvp( const char *file, char *const argv[]);