系统编程day05
一.知识点杂记
1.lable.so文件: 动态库 ,运行时动态加载。
2.(8M)栈: 放入局部变量, 形参, 函数返回地址
3.全局变量区: bss未初始化的数据, Data区初始化的
4.fprintf(fp,”father %d num:%d”,getid(),num) : 合并成字符串写入fp中
5.exit(): c库函数,会执行io库的清理工作,关闭所有的流
6._exit(): 使当前进程结束
二.进程的退出
一.僵尸进程与孤儿进程
1、僵尸进程: Linux中子进程消亡(默认不会释放pcb,此时为僵尸态),pcb由父进程调用回收函数。
2、孤儿进程: 父进程先消亡。
二.函数
一.exit函数
void exit(int status)
1.功能:让进程退出,并刷新缓存区
2.参数:status:进程退出的状态
3.返回值:缺省
4.属于库函数:
退出状态,终止的进程会通知父进程,自己使如何终止的。如果是正常结束(终
止),则由exit传入的参数。如果是异常终止,则有内核通知异常终止原因的状态。任
何情况下,父进程都能使用wait,waitpid获得这个状态,以及资源的回收。
5.注意:不管函数调用层次多深,调用exit函数后当前进程立马结束;
EXIT_SUCCESS 0 :正常退出
EXIT_FAILURE 1:非正常退出
全面回收工作。文件的关闭,堆空间的释放,缓冲区的清理。
6.示例
二._exit函数
该函数属于系统调用;
1.函数原型:void _exit(int status);
2.功能:让进程退出,不刷新缓存区(只会关闭已打开的文件,其他不管)
3.参数:status:进程退出状态
4.返回值:缺省
5.示例:
三.atexit函数
int atexit(void (*function)(void));
1.功能:注册进程退出前执行的函数
2.参数:function:函数指针,指向void返回值void参数的函数指针
3.返回值:成功返回0,失败返回非0
4.注: 当程序调用exit或者由main函数执行return时,所有用atexit注册的退出函数,将
会由注册时顺序倒序被调用
5.示例:
三.等待函数
一.wait函数
pid_t wait(int *status);
1.功能:该函数可以阻塞等待任意子进程退出并回收该进程的状态;
一般用于父进程回收子进程状态。
2.参数
status 进程退出时候的状态(退出状态(32Bit)包括退出值(8Bit)):
如果不关心其退出状态一般用NULL表示;
如果要回收进程退出状态,则用WEXITSTATUS回收。
3.返回值:成功 回收的子进程pid;失败 -1;
4.宏:
WIFEXITED(status) 判断是不是正常结束
WEXITSTATUS(status) 若正常结束则使用这个宏去返回状态
WIFSIGNALED(status) 判断是不是收到了信号而终止的
WTERMSIG(status)如果是信号终止的,那么是几号信号
5.注意:
如果所有的子进程都在运行,在阻塞(进程运行过程中,某条件未满足导致当前进
程被迫进入等待状态);
如果一个子进程终止,正在等待的父进程则获得终止状态,获得子进程的状态后,
立刻返回。
如果没有子进程,则立即出错退出。
6.示例
二.waitpid函数
pid_t waitpid(pid_t pid, int *status, int options);
pid:
小于-1 回收指定进程组内的任意子进程;
等于-1 回收任意子进程,组内外;
等于0 回收和当前调用waitpid一个组的所有子进程,组内;
大于0 回收指定ID的子进程;
1.status:子进程退出时候的状态
如果不关注退出状态用NULL;
2.options 选项:0 表示回收过程会阻塞等待;
WNOHANG 表示非阻塞模式回收资源。
3.返回值:成功 返回接收资源的子进程pid
失败 -1,0
4.示例:
四.exec族
启动一个已存在的外部程序
1.用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函时,
该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建; 新进程,所以调用exec前后该进程的id并未改变。
2.进程角度:代码段被替换(老进程被新进程替换)
新代码段走完后,a.out结束
3.六种以exec开头的函数,统称exec函数;
#include <unistd.h>
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]);int execle(const char *path, const char *arg, ..., char *const envp[]);
int execle(const char *path, const char *arg, ..., char *const envp[]);int execve(const char*path,char*const argv[],char*const evnp[]);
int execlp(const char *file, const char *arg, ...);int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
4.函数区别
1.前4个使用路径名作为参数,后面两个使用文件名做参数当filename中,含有/时视为路径名,否则就按PATH变量,在指定目录下查找可执行文件。
2.相关的参数表传递,l表示list,v表示vector;
execl,execlp,execle,需要将参数一个一个列出,并以NULL结尾。
execv,execvp,execve,需要构造一个参数指针数组,然后将数组的地址传入。
3.以e结尾的函数,可以传入一个指向环境字符串的指针数组的指针。其他未指定环境
变量,使用父进程继承过来的。execve 是真正的系统调用。
4.这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回,如果调用
出错则返回-1,所以exec函数只有出错的返回值而没有成功的返回值。
5.system函数
该函数为系统函数
(1)函数原型:int system(const char *command);
(2)底层实现:fork+exec ,(快捷的exec)
(3)功能:使用该函数可以将shell命令直接在代码中执行;
(4)参数:command:要执行的shell命令;
(5)返回值:成功 0,失败 -1;
(6)调用:system("vim 1.c");