Linux System Programming 33 Process Environment-Process termination method and exit() atexit() _exit()

1 main function

当前进程的出入口

2 The termination method of the process is very important and must be remembered clearly!

正常终止: 
		从main函数返回:  return 0
		调用exit : exit(0) / exit(1) ...  是库函数
		调用 _exit 或 _Exit    是系统调用
		最后一个线程从其启动例程返回
		最后一个线程调用 pthread_exit
		  	
异常终止:
		调用 abort,发送一个 abort 信号给当前进程,杀掉当前进程
		接到一个信号并终止
		最后一个线程对其取消请求作出响应

atexit() 钩子函数

NAME
exit-cause normal process termination, cause normal process termination

SYNOPSIS
#include <stdlib.h>

   void exit(int status);

DESCRIPTION
The exit() function causes normal process termination and the value of status & 0377 is returned to the parent (see wait(2)).
All functions registered with atexit(3) and on_exit(3) are called, in the reverse order of their registration.
When exit() is called to terminate the process normally, all functions registered with the atexit() and on_exit() hook functions will be called, in the reverse order of their registration at the time,

0377 octal 11 111 111, the lower eight bits are reserved, that is, the size of char, that is, the return value is: -128 ~~ +127


The hook function
atexit-register a function to be called at normal process termination
will be called when the process terminates normally.

Kind of like the destructor of C++

SYNOPSIS
#include <stdlib.h>

   int atexit(void (*function)(void));

Experiment; hook function

#include <stdio.h>
#include <stdlib.h>


static void f1(void)
{
	puts("f1() is working!");
}

static void f2(void)
{
	puts("f2() is working!");
}

static void f3(void)
{
	puts("f3() is working!");
}


int main()
{
	puts("Begin!");
	
	// 此处并不是代表函数调用,只是将目标函数挂在钩子函数上
	// 并不实现调用,而是在在进程正常终止的时候,即exit()的时候逆序调用
	atexit(f1);
	atexit(f2);
	atexit(f3);

	puts("End!");
	exit(0);
}




mhr@ubuntu:~/work/linux/进程环境$ gcc test.c 
mhr@ubuntu:~/work/linux/进程环境$ ./a.out 
Begin!
End!
f3() is working!
f2() is working!
f1() is working!
mhr@ubuntu:~/work/linux/进程环境$ 

The significance of the hook function is that when opening multiple files, in order to prevent memory leaks, the usual practice is to close all previously opened files when the current file fails to open. If there are too many previously opened files, then close Too many files are very inconvenient, so you can use the hook function to solve it. After each successful opening of a file, immediately mount the closing operation on atexit(), so that as long as exit() is encountered, the previous file will be automatically closed.


_EXIT(2) Linux Programmer’s Manual _EXIT(2)

NAME
_exit, _Exit - terminate the calling process

SYNOPSIS
#include <unistd.h>

   void _exit(int status);

   #include <stdlib.h>

   void _Exit(int status);

_exit VS exit

The dotted box in the figure represents the process space.
Executing exit() will execute the hook function, IO cleanup, and finally call _exit() to end the current process, which is a library function.
Executing _exit() will directly end the current process, which is a system call

Insert picture description here

So when to use exit() and when to use _exit()?

Fake code:

int func() 
{
	return 0/1/2; 返回 0 或 1 或 2
}

int main()
{
	int f;
    f = func();
    ......
    ......
	switch(f)
	{
		case 0:
		case 1:
		case 2:
		default:
		  		
	}
}

Assuming that our switch(f) does not go 1 2 3 at this time, and the fourth possibility appears, then we will go to the default branch. Many people will directly call exit() on the default branch to end the process. But things are often not that simple, because the reason for this situation may be that there is a problem with the code in the middle, and it is most likely that the writing is out of bounds and overwriting the space of my variable f. So in this case, if exit() is called directly in the default branch, then many hook functions will be called, and many IOs will be refreshed or synchronized, so that the current dirty data will be refreshed to the file, and the hook function Some content has been released or updated, further spreading the current bug! ! ! . So in this case, don't even think about the default branch, just call _exit() to exit the process, don't do any actions, don't call IO cleanup, hook functions, and exit the current process directly. Or abort() sends a signal to the current process to kill the current self, and get an error scene by the way.

Guess you like

Origin blog.csdn.net/LinuxArmbiggod/article/details/106041356