Linux浅谈进程2
2017-12-14 11:48
381 查看
此篇博客作为上一篇博客的补充
Linux浅谈进程1
fork()
vfork()
关于fork()函数
进程创建的一般过程
给新建的进程分配一个内部的标识符,在内核中分配PCB。
复制父进程的环境
为进程分配资源(代码,数据,堆栈)
父进程地址空间的内容也复制到新的进程空间中
将该进程放到就绪队列中。
向父进程返回子进程的进程号,对子进程返回0
当一个进程fork出一个子进程后,就有两个二进制代码相同的进程,并且运行到相同的地方,但每个进程都将开始执行自己的代码。
fork()调用失败的原因
系统中进程太多了
或实际用户的进程数超过了限制(每台电脑都有一个进程的最大数)
系统不支持fork()函数,(如windows)
vfork函数
也是用来创建子进程(在fork函数没有出现写时拷贝时出现的,性能高,但是有Bug)
子进程一定先于父进程执行。
子进程调用exec或者exit之后父进程才能执行
vfork与fork区别
fork:父子进程交替运行。vfork:子进程运行,父进程阻塞,直到子进程运行结束(创建出子进程,子进程运行完了才会运行父进程),程序最后用exit(0)进程退出
fork实现了写时拷贝。vfork就算是写也不拷贝
vfork必须使用exit或excl
就算是fork实现了写时拷贝,性能也没有vfork高
vfork虽然性能高,但是每个系统上的vfork都有问题,不要使用
代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
进程常见退出方法
正常终止
正常退出返回码为0
1. 从main返回
2. 调用exit
3. _exit
异常退出:
ctrl+C
kill
abort()
查看进程退出码
可以用echo$?查看进程的退出码
echo $?:查看上一个退出码 退出码返回0~255 只用了int的8个比特位,其余位有别的用途,比如,程序是否是正常退出,如果是异常退出,是什么原因导致异常退出
exit所做的工作
执行用户通过atext或on_exit定义的清理函数
关闭所有打开的流,所有的缓冲数据均被写入
调用_exit.
回调处理函数atexit(函数名):在程序结束前执行。有32个上限,运行顺序与定义顺序相反
_exit与exit区别
_exit()直接终止,清理缓冲区。
exit()直接退出程序
_exit是系统调用,exit最终也会调用_exit
进程的撤销(销毁)
关闭软中断
回收资源(如关闭文件)
将进程的状态置为僵尸态
写记账信息
转进程调度
进程等待就可以很好的解决这个问题
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
进程等待方法
wait
waitpid
wait
wait:做的三件事
阻塞当前进程,直到子进程退出才返回
回收子进程残留资源
获取子进程退出信息(状态)
waitpid
用代码看一下
结果为:
我们通过结果可以看出,进程正常退出。
用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
替换函数:
有六种以exec开头的函数,都统称为exec函数
函数解释:
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值
命名解释
l(list):表示参数采用列表
v(vector):表示参数采用数组
p(path):带p的函数会自动搜索环境变量PATH
e(env):表示自己维护环境变量
Linux浅谈进程1
进程的创建
进程创建的方式:fork()
vfork()
关于fork()函数
头文件为#include<unistd.h> pid_t fork(void) 返回值: 子进程返回0,父进程返回子进程id,出错返回-1
进程创建的一般过程
给新建的进程分配一个内部的标识符,在内核中分配PCB。
复制父进程的环境
为进程分配资源(代码,数据,堆栈)
父进程地址空间的内容也复制到新的进程空间中
将该进程放到就绪队列中。
向父进程返回子进程的进程号,对子进程返回0
当一个进程fork出一个子进程后,就有两个二进制代码相同的进程,并且运行到相同的地方,但每个进程都将开始执行自己的代码。
fork()调用失败的原因
系统中进程太多了
或实际用户的进程数超过了限制(每台电脑都有一个进程的最大数)
系统不支持fork()函数,(如windows)
vfork函数
也是用来创建子进程(在fork函数没有出现写时拷贝时出现的,性能高,但是有Bug)
子进程一定先于父进程执行。
子进程调用exec或者exit之后父进程才能执行
vfork与fork区别
fork:父子进程交替运行。vfork:子进程运行,父进程阻塞,直到子进程运行结束(创建出子进程,子进程运行完了才会运行父进程),程序最后用exit(0)进程退出
fork实现了写时拷贝。vfork就算是写也不拷贝
vfork必须使用exit或excl
就算是fork实现了写时拷贝,性能也没有vfork高
vfork虽然性能高,但是每个系统上的vfork都有问题,不要使用
进程的终止(结束)
进程退出的场景:代码运行完毕,结果正确
代码运行完毕,结果不正确
代码异常终止
进程常见退出方法
正常终止
正常退出返回码为0
1. 从main返回
2. 调用exit
3. _exit
异常退出:
ctrl+C
kill
abort()
查看进程退出码
可以用echo$?查看进程的退出码
echo $?:查看上一个退出码 退出码返回0~255 只用了int的8个比特位,其余位有别的用途,比如,程序是否是正常退出,如果是异常退出,是什么原因导致异常退出
exit所做的工作
执行用户通过atext或on_exit定义的清理函数
关闭所有打开的流,所有的缓冲数据均被写入
调用_exit.
回调处理函数atexit(函数名):在程序结束前执行。有32个上限,运行顺序与定义顺序相反
_exit与exit区别
_exit()直接终止,清理缓冲区。
exit()直接退出程序
_exit是系统调用,exit最终也会调用_exit
进程的撤销(销毁)
关闭软中断
回收资源(如关闭文件)
将进程的状态置为僵尸态
写记账信息
转进程调度
进程的等待
进程等待是一个很重要的过程,如果子进程退出,父进程不回收资源,就会造成我们之前博客讲过的“僵尸进程”的问题,从而导致内存泄漏进程等待就可以很好的解决这个问题
父进程通过进程等待的方式,回收子进程资源,获取子进程退出信息
进程等待方法
wait
waitpid
wait
//#include<sys/types.h> //#include<sys/wait.h> //头文件 pid_t wait(int* status) 返回值:成功返回被等待进程pid,失败返回-1 参数:输出型参数,获取子进程的退出状态,不关心可以设置为NULL
wait:做的三件事
阻塞当前进程,直到子进程退出才返回
回收子进程残留资源
获取子进程退出信息(状态)
waitpid
pid_t waitpid(pid_t pid,int *status,int options); 返回值: 当正常返回时waitpid返回收集到的子进程的进程ID 如果设置了选项WHOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0 如果调用中出错,则返回-1,这是errno会被设置成相应的值以指示错误所在 参数: pid: pid=-1,等待任一个子进程,与wait等效。 pid >0,等待其进程ID与pid相等的子进程。 status: WIFEXITED(status):若为正常终止子进程返回的状态,则为真(查看进程是否正常退出) WEXITSTATUS(status):若WEXITSTATUS非零,提取子进程退出码(查看进程的退出码) options: WNOHANG:若pid指定的子进程没有结束,则waitpid()函数返回0,不等待,若正常结束,返回该子进程的ID。
用代码看一下
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<string.h> #include<sys/wait.h> int main() { pid_t pid; if((pid=fork())==-1) { perror("fork"); exit(1); } if(pid==0) { int i=0; printf("this is maomaochong\n",getpid()); sleep(1); exit(-1); } else { int status; pid_t w=wait(&status); if(w==-1) perror("wait"); else printf("parent w=%d\n",w); if(WIFEXITED(status)) { printf("exitcode=%d\n",WEXITSTATUS(status)); } else if(WIFSIGNALED(status)) { printf("signum=%d\n",WTERMSIG(status)); } } }
结果为:
我们通过结果可以看出,进程正常退出。
进程程序替换
替换原理用fork创建子进程后执行的是和父进程相同的程序(但有可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。
替换函数:
有六种以exec开头的函数,都统称为exec函数
#include<unistd.h> 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 execve(const char *path,char *const argv[], char *const envp[]);
函数解释:
这些函数如果调用成功则加载新的程序从启动代码开始执行,不再返回。
如果调用出错则返回-1
所以exec函数只有出错的返回值而没有成功的返回值
命名解释
l(list):表示参数采用列表
v(vector):表示参数采用数组
p(path):带p的函数会自动搜索环境变量PATH
e(env):表示自己维护环境变量
相关文章推荐
- 浅谈Linux进程等待
- 浅谈Linux的进程
- 初学linux ---浅谈进程
- 浅谈Linux中的僵尸进程
- 浅谈Linux进程调度过程
- 浅谈Linux进程
- 分享:linux进程浅谈
- 浅谈Linux进程
- 浅谈linux下多进程编程及其同步机制
- Linux01-Linux进程管理浅谈43
- 浅谈linux性能调优之十七:进程绑定与中断绑定
- 浅谈Linux系统中如何查看进程
- 浅谈操作系统是如何工作的及简单的进程调度的linux实现
- 【Linux系统编程】浅谈进程地址空间与虚拟存储空间
- 浅谈 java线程 和 linux进程
- 浅谈Linux系统中如何查看进程 ——ps,pstree,top,w,全解
- 浅谈Linux下的syslog守护进程 推荐
- 写给linux系统管理员看的systemd 二 给定Service拥有哪些进程(systemd作者blog翻译过来的)
- 12个Linux进程管理命令介绍
- Linux之进程环境