接上午的问题 O_CLOEXEC, execve呢, 就是exec系列函数中的一个,具体可以参见Unix环境高级编程第二版8.10节.

当进程调用一种exec函数时, 该进程执行的程序完全替换成新进程,而新程序则从其main函数开始执行. 因为exec并不创建新进程,所以前后的进程ID并未改变. exec只是用一个全新的程序替换了当前进程的正文,数据,堆和栈段.

现在来测试一下O_CLOEXEC这个参数的作用.

貌似, 一般来说, exec会在folk之后调用. 为了让例子看起来更简单, 我就在当前程序中调用exec. 测试的大概流程是这样.

不带O_CLOEXEC这个参数, 打开一个文件. 然后再exec一个sleep程序, sleep 10秒.
程序运行时, 新开一个shell拿lsof观察被打开的文件, 是否被占用.

如果不带O_CLOEXEC参数打开文件, 在exec之后, 这个文件使用被占用.

如果带O_CLOEXEC参数打开文件, exec之后, 文件就不再被占用了.

cloexec.c

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, const char *argv[])
{
    int fd = open("cloexec.c",O_RDWR);
    printf("%d\n",fcntl(fd, F_GETFD, FD_CLOEXEC));
    sleep(5);

    execl("/tmp/cloexec/sleep",(char *)0);

    return 0;
}

sleep.c

#include <unistd.h>
#include <stdio.h>

int main(int argc, const char *argv[])
{
    sleep(5);
    printf("sleep done\n");
    return 1;
}