return退出
return是一种更常见的退出进程方法。执行return n等同于执行exit(n),因为调用main的运行时函数会将main的返
回值当做 exit的参数。
进程退出返回值的意义:
return以及exit给与的数据其实就是进程的退出码
作用: 一个程序运行起来肯定是为了完成一个任务,但是这个任务完成的怎么样外界怎么知道呢?因此就必须有这个进程的退出码,来表示当前进程任务处理的结果。不管是return还是exit,都需要我们给出一个进程的返回值exit(0), return 0;给出的返回值,是进程的返回值因为一个进程就是为了调度运行一个程序, 完成一个任务的(但是任务完成有好有坏),就必须得有一种方式能够告诉我们这个任务完成的怎么样? (返回值的作用)
内存管理方式
分段式内存管理:将一个整体的地址空间划分为多个段(代码段,全局数据段,堆区,共享区,栈区,环境变量,运行参数…)
优势/作用:非更加利于编译器对于地址的管理。
重要的两个要素:段表,地址组成 虚拟地址组成:段号,段内的偏移量
段表:是一种数据结构,其中描述的信息,段号:物理内存的一个起始地址 映射:虚拟地址组成+段表
通过段号找到段表项,得到一块物理内存的起始地址
物理内存起始地址+偏移量就是实际数据存储在物理内存中的位置
分页式内存管理:将一个整体的地址空间划分 为大量的小的分页page (当前一般默认都是4096字节为一页)
作用:实现数据的离散存储,提高内存利用率
段页式内存管理:先将地址空间进行分段,然后在每个分段内使用分页进行管理(集合了分段式和分页式的优势) 映射:虚拟地址组成(页号+页内偏移)
页表(页号+物理块地址+访问权限+缺页中断…)
段页式:先对虚拟地址空间进行分段,在每个段内进行分页管理,集合分段与分页各自的优势进行内存管理
好处:
- .每个进程都有一个完整独立的虚拟地址空间,则地址可以随便使用,不用担心冲突(地址管理更加方便)
- 进过页表映射可以将数据存储在物理内存的任意位置,实现数据的离散式存储,提高内存利用率
- 在进行页表映射的之后可以进行访问权限的控制
进程等待
进程等待必要性
wait方法
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值: 成功返回被等待进程pid,失败返回-1。
参数: 输出型参数,获取子进程退出状态,不关心则可以设置成为NULL
(子进程没有退出会一直等待,子进程退出会直接退出)
waitpid方法
pid_ t waitpid(pid_t pid, int status, int options);
返回值: 当正常返回的时候waitpid返回收集到的子进程的进程ID;如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0; 如果调用中出错,则返回*-1**,这时errno会被设置成相应的值以指示错误所在; 参数: pid:
Pid=-1,等待任一个子进程。与wait等效。
Pid>0.等待其进程ID与pid相等的子进程。
status:
WIFEXITED(status): 若为正常终止子进程返回的状态,则为真。(查看进程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子进程退出码。(查看进程的退出码)
options:
WNOHANG: 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若正常结束,则返回该子进程的ID。0是默认阻塞
故:waipid(-1,&status,0)与wait等价,都是没获取到就堵塞,获取任意一个子进程的返回值
注意:
如果子进程已经退出,调用wait/waitpid时,wait/waitpid会立即返回,并且释放资源,获得子进程退出信息。
如果在任意时刻调用wait/waitpid,子进程存在且正常运行,则进程可能阻塞。
如果不存在该子进程,则立即出错返回。
获取子进程status
wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。如果传递NULL,表示不关心子进程的退出状态信息。否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位,高16位暂时不关心):
低16位中的高8位保存进程退出码,之后有一个coredump标志位占据一个比特位,coredump文件很大,默认情况下是关闭的。
注意:通过wait获取的返回值,有多个信息,其中进程的退出码保存到高8位中,并且只用一个字节来保存,即(0~255),多了采取截断、
因此要获取一一个进程的退出码,首先得确定这个进程是否是正常退出的,如果是,才有意义。
代码中关心的问题:
如何判断进程是否是正常退出:取出status中的低7位; status & 0x7f(就是0111 1111)== 0正常退出,否则异常退出
如何从status中取出退出码:取出status中的低1 6位中的高8位 (status >> 8) & 0xff(1111 1111) 向右移动8位
问:exit()和status是怎么链接上的?
阻塞等待代码演示
int main() { pid_t pid; pid = fork(); if(pid < 0){ printf("%s fork error\n",__FUNCTION__); return 1; } else if( pid == 0 ){ //child printf("child is run, pid is : %d\n",getpid()); sleep(5); exit(257); } else{ int status = 0; pid_t ret = waitpid(-1, &status, 0);//阻塞式等待,等待5S printf("this is test for wait\n"); if( WIFEXITED(status) && ret == pid ){ printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status)); }else{ printf("wait child failed, return.\n"); return 1; } } return 0; } 运行结果: [root@localhost linux]# ./a.out child is run, pid is : 45110 this is test for wait wait child 5s success, child return code is :1.
进程的非阻塞等待方式:
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/wait.h> int main() { pid_t pid; pid = fork(); if(pid < 0){ printf("%s fork error\n",__FUNCTION__); return 1; }else if( pid == 0 ){ //child printf("child is run, pid is : %d\n",getpid()); sleep(5); exit(1); } else{ int status = 0; pid_t ret = 0; do { ret = waitpid(-1, &status, WNOHANG);//非阻塞式等待 if( ret == 0 ){ printf("child is running\n"); } sleep(1); }while(ret == 0); if( WIFEXITED(status) && ret == pid ){ printf("wait child 5s success, child return code is :%d.\n",WEXITSTATUS(status)); }else{ printf("wait child failed, return.\n"); return 1; } } return 0; }