进程概念
正在执行中的程序。
进程终止
有八种方式使进程终止:五种正常返回,三种异常终止。
五种正常返回为:
1. 从main函数返回;
2. 调用exit;
3. 调用_exit或_Exit;
4. 最后一个线程从其启动例程返回;
5. 从最后一个线程调用pthread_exit;
三种异常终止方式为:
6. 调用abort;
7. 接到一个信号;
8. 最后一个线程对取消请求做出相应。
如何创建进程
//三种方式
1. pid_t fork()
2. exec()
3. int system()
fork()函数
fork()函数通过系统调用创建一个与原来进程(父进程)几乎完全相同的进程(子进程是父进程的副本)
eg:
父子进程相同处:全局变量,.data, .text,栈,堆,环境变量,用户ID,宿主目录,进程工作目录,信号处理方式。
父子进程不同之处:进程ID, fork返回值,父进程ID,进程运行时间,闹钟,未决信号集now:
看起来子进程像是复制了父进程0-3G的虚拟内存空间,以及父进程的PCB,但PID不同,然后映射至物理内存上。实际上fork()
做了如下处理“读时共享,写时复制”来节省了内存开销。
pid_t fork();
fork()函数具有两个返回值。其返回值分别为0和大于0的值。
- 返回值等于0,其为子进程。
返回值大于0,其为父进程。
循环创建N个子进程
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main(void) {
for(int i = 0; i < n; i++) {
pid_t pid = fork();
if(pid == -1) {
perror("fork err");
exit(1);
} else if (pid == 0) {
printf("i am parent\n");
} else {
//出口
break;
}
}
return 0;
}
exec函数族
#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *file,
char *const argv[],
char *const envp[]);
int execle(const char *path,
const char *arg, ...,
char * const envp[]);
后 缀 | 操作能力 |
---|---|
l | 希望接收以逗号分隔的参数列表,列表以NULL指针作为结束标志 |
v | 希望接收到一个以NULL结尾的字符串数组的指针 |
p | 是一个以NULL结尾的字符串数组指针,函数可以DOS的PATH变量查找子程序文件 |
e | 函数传递指定参数envp,允许改变子进程的环境,无后缀e时,子进程使用当前程序的环境 |
使用exec函数启动的进程,替换原有的进程,其进程号仍为调用exec函数的进程的进程号。
- exec函数需要注意末尾加上作为NULL的结束标志。
- 其第一个argv,其为argv[0]。
- exec函数执行完后,不再执行该函数后的内容。
- exec函数的判断直接使用
perror(“exec err”);
即可
孤儿进程
父进程死于子进程结束前。子进程的父亲ID即变为init进程的进程号。
僵尸进程
子进程死亡后父进程没有对子进程进行回收。
这将导致系统资源的浪费,尤其是再服务器中,长时间不会停止,如果一旦产生僵尸进程,则服务器资源将会被耗尽。
由于子进程已经死了,使用KILL命令也无法消除掉它。
进程回收
int wait(int *status);
//作用:阻塞等待子进程退出、
//回收子进程残留资源、
//获取子进程结束状态。
//status用来获取状态信息
一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。
当进程终止时,操作系统隐式回收机制会:1.关闭所有文件描述符 2.释放用户空间分配的内存。内核的PCB仍存在。其中保存进程的退出状态。(PCB位于 /usr/src/linux-haeders-3.16.0-30/include/linux/sched.h
)
宏函数 | 作用 |
---|---|
WIFEXITED(status) | 如果结果非0,则进程正常结束 |
WEXITSTATUS(status) | 如果WIFEXITED(status)为真,则此宏获取进程退出状态 |
WIFSIGNALED(status) | 如果结果非0,则进程异常终止 |
WTERMSIG(status) | 如果WIFSIGNALED(status)为真,则此宏获取进程终止信号的编号 |
pid_t waitpid(pid_t pid, int *status. int options);
//参数:
//pid == -1 等待任一子进。
//pid > 0 等待进程ID与pid相等的进程。
//pid == 0 等待其组ID等于调用进程组ID的任一子进程。
//pid < -1 等待其组id等于pid的绝对值的任一子进程。
//返回值:
// > 0 :返回清理掉的子进程ID
// - 1 :无子进程
// = 0 :参数3为WNOHANG,且子进程在运行。
多进程调试
set follow-fork-mode parent //命令设置GDB在fork后跟踪父进程
//不设置默认为父进程
set follow-fork-mode child //命令设置GDB在fork后跟踪子进程