进程环境
进程环境
一个exe的生命周期
启动
内核使用exec
启动C函数的app,exec
在main
之前会调用另一个函数_start
,负责从内核那里接收命令行参数和环境变量,设置好这些之后再调用main函数。
退出
进程正常终止:
- 1.从main函数返回,即retrun 0;
- 2.调用exit,即在main函数内或者其他会被main调用的函数体内调用exit();
- 3.调用
_exit
或_Exit
,即在main函数内或者其他会被main调用的函数体内调用_exit
或_Exit
;, - 4.最后一个线程从其所在进程返回;
- 5.最后一个线程在其所在进程调用
pthread_exit
。
进程异常终止:
- 6.调用
abort
; - 7.进程接收到信号;
- 8.进程中最后一个线程最取消做出响应。
可以使用exit、_exit
和_Exit
函数来正常终止程序,第一个函数和后面两个函数区别是,exit会进行一些资源清理工作,然后返回内核,而_exit和_Exit
则不清理立即返回内核_exit和Exit
等价
注意除非通过return语句来返回,或者通过exit( )来退出才会调用清理函数,_exit和_Exit函数是不会调用清理函数的
注册自己的清理函数
int atexit(void (*function)(void));
这个函数在exit
和main
的return才会调用,最多可以注册32个,重复注册的函数会重复调用,先注册的最后执行,类似于栈
void exit1()
{
printf("exit 1\n");
}
void exit2()
{
printf("exit 2\n");
}
void exit3()
{
static int a=0;
printf("exit 3,static num=%d\n",a++);
}
int main(int argc, char const *argv[])
{
atexit(exit1);
atexit(exit2);
atexit(exit3);
atexit(exit3);
printf("main in\n");
return 0;
}
//main in
//exit 3,static num=0
//exit 3,static num=1
//exit 2
//exit 1
环境变量
char *getenv (const char *name);
int putenv (char *string);
int setenv (const char *name, const char *value, int replace);
int unsetenv (const char *name);
跨函数跳转
// 联合使用的
int setjmp (jmp_buf env);
void longjmp (struct jmp_buf_tag env[1], int val);
第一次调用setjmp函数时,其返回值为0,后续调用返回值由传入longjmp的val值决定
- 在想要跳转的地方设置
int setjmp (jmp_buf env)
,变量存放了当前的栈信息,一般是全局变量 - 在需要跳出也就是
goto
的地方放置longjmp (struct jmp_buf_tag env[1], int val)
,第一个参数就是1中的栈信息,第二个参数是1中的返回值,其实也就是可能在多处设置了setjmp
,可以选择跳到哪里去 - 这里的跳转还是有点麻烦的,全局变量和静态变量不受影响因为不在栈中,其他的情况有点不太好确认的,与编译器优化也有关系
- 没必要研究这个了, https://blog.csdn.net/qq_34793133/article/details/80475323, c++可以使用异常
资源限制
int getrlimit (rlimit_resource_t resource, struct rlimit *rlimits);
int setrlimit (rlimit_resource_t resource, const struct rlimit *rlimits);