Linux浅谈进程2
来源:互联网 发布:淘宝工商执照可信吗 编辑:程序博客网 时间:2024/05/29 19:57
此篇博客作为上一篇博客的补充
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浅谈进程2
- 浅谈linux进程调度
- 浅谈Linux进程
- 初学linux ---浅谈进程
- Linux浅谈进程
- 浅谈Linux进程等待
- 浅谈Linux中的僵尸进程
- 浅谈Linux中的僵尸进程
- 浅谈Linux系统中如何查看进程
- 浅谈Linux系统中如何查看进程
- 浅谈 java线程 和 linux进程
- 浅谈进程
- 浅谈进程2--进程优先级,进程的创建执行
- 浅谈linux下多进程编程及其同步机制
- 【Linux系统编程】浅谈进程地址空间与虚拟存储空间
- 浅谈linux系统下的进程通信之管道pipe
- 浅谈并发服务器---多进程并发---2
- Windows进程/线程浅谈
- Android-问题列表-转载
- list<T>删除不满足条件的数据
- 拆轮子系列之剖析EventBus源码
- Socket基础使用
- 把一段话的每个首字母大写,substring,spilt,length,length(),size()
- Linux浅谈进程2
- VNC远程桌面的配置
- 删除WINDOWS10中讨厌的微软拼音
- 旋转矩阵与欧拉角
- C/C++中使用PlaySound()播放音乐
- Python爬虫实例(3)-用BeautifulSoup爬取多个可翻页网页上的多张照片
- 浅显易懂了解JavaScript回调函数
- poj 3259 Bellman-Ford判断负权环
- 测试与开发(一)