对于mian()函数而言,执行前也需要先执行一段引导代码才会去执行main()函数,该部分的代码包含构建c语言的运行环境等配置,如清理bss段等。
在使用gcc去编译程序的时候,使用gcc -v xxx.c可见链接过程。在编译完成后可见xxx.out文件。
当运行一个程序时,加载器将程序需要的程序加载内存中运行(编译时用到的是连接器,运行时用到的是加载器)。argc与argv的参数输入就在这个部分实现;加载器->引导代码->mian()。
程序结束,正常结束使用return、exit、_exit等。
非正常结束程序是通过自己或它程序发送信号实现程序终止如ctrl+c(linux而言)。
atexit()向系统注册进程终止处理函数。
int atexit(void (*func)(void))
void func1(void)
{
printf("func1\n");
}
int mian(void)
{
printf(......);//①
atexit(func1);//②
printf(......);//③
return 0;
}
执行顺序为①->③->②打印func1。当多个atexit函数注册时,先注册的后执行幕后注册的先执行。其原因是atexit是用一个栈去存储这些注册的函数指针的。
return和exit的效果其实是一样的,但_exit(0)不会去执行atexit注册的函数。return和exit就类似于回调函数,但_exit(0)是内核直接终止了进程,不会对现场进行清理和打扫。(回调函数,作为参数传递给另一个函数,在被调用函数执行完成后再执行)。
进程环境
环境变量,环境就是周围的东西,可用拿来使用。使用echo $PATH打印当前PATH,使用export打印所有的环境变量.所以进程所在环境变量存在进程环境表中。
当前进程中可以直接使用环境变量表中的变量environ。
extern char **environ//本质是一个字符串数组
int i=0;
while(NULL!=environ[i])
{
printf(。。。。。。,environ[i]);
i++;
}
char *getenv(const char *name);查找环境变量。
int setenv(const char *name, const char *value, int overwrite);设置环境变量。
clearenv()清理环境变量。
等等
进程运行的虚拟地址空间,让每个进程运行在独立的虚拟空间,认为整个内存只有自己一个在运行,但实际上是独立分时使用。
虚拟空间,说给你,但实际不给你,毕竟程序不是自己就开始原地运行的,只有在用到的时候才会给你用到的内存大小。
意义,实现内存隔离提高安全性,多进程同时运行时,当链接地址==运行地址时,程序运行虚拟地址映射,所在的地址从0开始,程序不用关系真实的物理地址是多少。这就是gcc编译时不用提供链接地址的原因。
进程,进程是一个动态的过程不是静态的实际物质,静态->在硬盘里;动态->在RAM内存里。内进程控制块PCB,核中有专门用于管理进程控制的数据结构。
进程ID,是PCB中的一个元素,用于标识唯一表示进程的区分,使用ps -aux打印进程信息,PID 1是内核->用户态进程。
getpid()//得到自己的pid
getppid()//得到父进程pid
getuid()//得到当前进程用户ai
getgid()//得到当前组id
进程PID结束后,id不会复用,所以开机pid数字2w以上是正常的。getpid()本质是从pcb中读取的。
多进程调度原理,操作系统要求多进程同时运行,否则不干活;本质上是宏观的并行,围观的串行,单核cpu在同一时间只能干一件事,但这个事情是极短的,所以在宏观上可看作并行,现代操作系统最小调度单位是线程而不是进程。
调度器,依照进程所需时间,级别,情况等进行调度安排时间分配。