进程
每个进程都有一个非负整数表示的唯一ID,叫做pid
pid=0 交换进程 进程调度
pid=1 init进程 系统初始化
getpid 获取自身的进程标识符
getppid 获取父进程的进程标识符
父进程与子进程
进程A创建了进程B
A父进程 B子进程
父子进程是相对概念
C程序的存储空间的分配
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-th1YSyos-1615252193600)(C:\Users\Hasee\AppData\Roaming\Typora\typora-user-images\image-20210304151124468.png)]
栈 函数调用返回地址 局部变量
堆 malloc
bss段 函数外 未初始化的数据
数据段 初始化过的变量
正文段 代码段
用fork函数创建一个进程
pid_t fork(void);
//fork函数调用成功,返回两次
//返回0 代表当前进程是子进程
//返回非负数 代表当前进程是父进程
//调用失败,返回-1
----------fork() 1父-------------------
1子-------------------
用vfork函数创建一个进程
vfork直接使用父进程存储空间,不拷贝
vfork保证子进程先运行,当子进程调用exit退出后,父进程才执行
其余用法同 fork
----------vfork() 2父-------------------
1子-------------------
新旧Linux 父子进程区别
旧Linux 全拷贝
新Linux 写时拷贝 copy on write
进程退出
正常退出
- Main函数调用return
- 进程调用exit(),标准C库 会先冲刷缓冲区
- 进程调用_exit()或 _Exit(),属于系统调用 直接退出
补充
- 进程最后一个线程返回
- 最后一个线程调用pthread_exit
异常退出
- 调用abort
- 当进程收到某些信号时,如ctrl+C
- 最后一个线程堆取消(cancellation)请求做出响应
#include <unistd.h>
void exit(int status);
void _exit(int status);
void _Exit(int status);
父进程等待子进程退出,并收集子进程的退出状态
调用wait函数(会返回一个状态码)
子进程退出状态不被收集,变成僵死进程(僵尸进程)
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
正常退出WEXITSTATUS(status) 读取 exit(i)返回值i
用waitpid非阻塞等待 子进程也会变成僵尸进程
孤儿进程
父进程如果不等待子进程退出,在子进程之前就结束了自己的“生命”,此时子进程叫做孤儿进程
Linux避免系统存在过多孤儿进程,init进程收留孤儿进程,变成孤儿进程的父进程
exec族函数
在调用进程内部执行一个可执行文件
exec函数执行成功后不会返回,调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。
#include <unistd.h>
extern char **environ;
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[]);
int execvpe(const char *file,
char *const argv[],char *const envp[]);
//path可执行文件的路径名字
//arg可执行程序所带的参数,第一个参数为可执行文件名字,没有带路径且arg必须以NULL结束
//file如果参数file中包含/,则将其视为路径名,否则视为PATH环境变量,在它所指定的各目录中搜寻可执行文件
perror() 打印错误原因
system函数
system()函数返回值 成功,返回进程状态值;sh不能执行,返回127;失败返回-1
system()是封装后的execl()
system()还会返回原始程序 继续执行代码
#include <stdlib.h>
int system(const char *command);
//()里 写原本要输的指令即可
popen函数
bisystem在应用中的好处:可以获取运行的输出结果
popen返回的是一个FILE 用fread读取
#include <stdio.h>
FILE *popen(const char *command, const char *mode);
//mode r输出 w输入
int pclose(FILE *stream);
获取运行的输出结果
popen返回的是一个FILE 用fread读取
#include <stdio.h>
FILE *popen(const char *command, const char *mode);
//mode r输出 w输入
int pclose(FILE *stream);