Linux系统调用:进程的终止

之前介绍了Linux的系统创建,主要是fork()函数和vfork()函数,现在再看看Linux进程的终止,主要的调用是_exit()和exit().

先看看两个函数的原型以及各自属于的头文件,可以发现这两个方法的区别

_exit()函数:

#include <unistd.h>

void _exit(int status);

从_exit()的头文件能够发现,_exit()是属于Linux的系统调用, 只能在Linux或者是Unix上才支持这个调用。

其中,status定了进程的终止状态,其父进程可以通过wait()函数来获取这个状态,从而进行之后的执行操作。当status为0时,表示进程正常退出,反之则是非正常退出。调用_exit()会使进程总是成功终止,也就是说_exit()方法从不会返回。

此处需要注意的是,虽然status定义成了整型,但实际上只有低8位可用,其原因就是当以信号(signal)终止一个进程的时候,shell会将变量$?置为128与信号之和,以表征这一事实。如果这与进程调用_exit()时所使用相同status值混杂起来,将令shell无法分辨。(这个地方不是很理解)

exit()函数:

#include <stdlib.h>

void exit(int status);

从exit()的头文件可以看出,exit()是C语言的库函数,所以所有的C语言都支持这个方法。

exit()在调用的时候要做得工作会比较多,主要有如下几个操作:

  1. 调用退出处理程序(通过atexit()和on_exit()注册的函数),并且在有多个退出处理程序时,执行顺序与注册顺序相反。
  2. 刷新stdio流缓冲区;
  3. 使用有status提供的值执行_exit()函数

我们通常在写程序的时候,在main()函数结尾只是用了return n;来结尾,在这个地方,return n; 就相当于exit(n),在结束的时候主函数会将返回值作为调用exit()函数的参数。这个地方本人有个疑问,在exit()函数调用_exit()时,其参数使用前面的n,而在_exit(int status)中,status为0表示程序正常结束,如果在return的时候,指定的n不为0,是一个其他的数,Linux内部会怎么处理呢?

其实在进程终止的时候,还有一些更细致的操作,由于本人目前能力有限,先不做讨论。


刚刚在前面提到了退出处理程序,现在来看看退出处理程序。

使用退出处理程序的原因就是,我们调用的exit()是C语言的库函数,而库函数对于进程的退出并没有实际控制的权利,所以无法在进程退出时调用系统特定的清理函数,所以退出处理函数就应运而生。

GUNC 提供了一下两种方式来注册退出处理函数:

#include <stdlib.h>

int atexit(void (*func)(void));

//退出处理函数的定义

void func(void) {
    /* performance */
}

需要注意的是:

  1. atexit()函数在出错的时候返回的是非0值,不仅仅是负值;
  2. 同时,在退出处理函数中如果访问了此前mian()函数中本地变量,那么main()函数的返回会导致未定义的行为;
  3. 当有多个退出处理程序的时候,退出处理程序的调用顺序与之策顺序是相反的,这一点的逻辑是,先注册的通常是更为基本的清理动作,可能需要在后续注册的函数后再执行;
  4. 一旦退出处理程序在无法返回——调用了_exit()或者因为信号而终止,其后的处理程序将不再执行。

以上的atexit()有两个局限,第一是退出处理程序不能获取当前进程退出时的状态,而根据进程退出状态来做相应的操作可以是支持的;第二就是不能给退出处理程序传递参数。

所以glibc提供了一个非标准的替代方法:on_exit()。其定义如下:

#define _BSD_SOURCE
#include <stdlib.h>

int on_exit(void (*func)(int, void *),void *arg);

//退出处理函数定义
void func(int status, void *arg) {
    /* Performace */
}

和atexit()函数类似,on_exit()的出错时返回值为非0。而on_exit()还不是所有标准都支持,还是应该尽量避免。

atexit()和on_exit()注册的函数属于同一个函数列表,在执行时与注册的顺序相反。

最后给一个例子仅供大家参考

#define _BSD_SOURCE
#include <stdlib.h>
#include <sys/types.h>
#include <stdio.h>

static void atexitFunc1(void) {
    printf("atexit function 1 called\n");
}

static void atexitFunc2(void) {
    printf("atexit function 2 called\n");
}

static void onexitFunc(int exitStatus, void *arg) {
    printf("on_exit function called: status=%d, arg=%ld\n",exitStatus, (long) arg);
}

int main(int argc, char *argv[]) {
    if(on_exit(onexitFunc, (void *) 10) != 0)
        perror("on_exit 1");
    if(atexit(atexitFunc1) != 0)
        perror("atexit 1");
    if(atexit(atexitFunc2) != 0)
        perror("atexit 2");
    if(on_exit(onexitFunc, (void *) 10) != 0)
        perror("on_exit 2");
    exit(2);
}

执行的结果如下:

on_exit function called: status=2, arg=20
atexit function 2 called
atexit function 1 called
on_exit function called: status=2, arg=10

由于刚开始学习Linux不久,有些理解可能有问题,希望各位大神多多海涵,希望和大家多交流

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值