open函数O_CLOEXEC作用

open函数的O_CLOEXEC参数官方文档给的解释是:

 O_CLOEXEC (Since Linux 2.6.23)
              Enable the close-on-exec flag for the new file descriptor.  Specifying this flag permits a program to avoid additional fcntl(2)  F_SETFD  operations  to
              set  the  FD_CLOEXEC flag.  Additionally, use of this flag is essential in some multithreaded programs since using a separate fcntl(2) F_SETFD operation
              to set the FD_CLOEXEC flag does not suffice to avoid race conditions where one thread opens a file descriptor at the same time as another thread does  a
              fork(2) plus execve(2).

翻译过来主要意思是:在创建时包含该flag,可以防止竞争的产生


open函数官方文档中有这么一句话:

By default, the new file descriptor is set to remain open across an execve(2) (i.e., the FD_CLOEXEC file descriptor flag described  in  fcntl(2)  is  initially
       disabled; the O_CLOEXEC flag, described below, can be used to change this default).  The file offset is set to the beginning of the file (see lseek(2)).

翻译过来主要意思是:FD_CLOEXEC默认是关闭的,文件描述符在fork或者fork+execve之后是默认打开的,具体点就是该文件被打开的引用计数+1了。


下面就使用代码验证下该功能:

vim cloexec.c


#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "unistd.h"
#include "string.h"
#include "errno.h"
#include "stdio.h"
#include "stdlib.h"
#include <sys/prctl.h>


int main(int argc, char *argv[])
{
    printf("there is %d param\n",argc);
    //int fd=open("/home/wade/test/a.txt",O_APPEND|O_RDWR|O_CLOEXEC);
    int fd=open("/home/wade/test/a.txt",O_APPEND|O_RDWR);
    if(fd == -1)
    {
        printf("open failed and reason is %s\n",strerror(errno));
    }
    printf("fd is %d\n",fd);
    pid_t expid=fork();
    if(expid == 0)
    {


        char fdptr[5];
        memset(fdptr,0,5);
        sprintf(fdptr,"%d",fd);
        char* execargv[]={fdptr,NULL};
        char *newenviron[] = { NULL };


        int exret = execve("./print",execargv,newenviron);


        if(exret == -1)
            printf("execve returned and error is %s\n",strerror(errno));
    }
    printf("children pid is %d \n",expid);


    char c_write[2]="a";
   

   while(1)
    {
        int wret = write(fd,&c_write,2);
        if(wret==-1)
        {
         printf("master write %d  to a.txt and reason is %s\n",wret,strerror(errno));
        }
        else
        {
            printf("master write %d  to a.txt \n",wret);
        }


        sleep(2);
    }


}


vim print.c 

#include "errno.h"
#include "stdio.h"
#include "stdlib.h"
#include <unistd.h>
#include "string.h"
int main(int argc, char *argv[], char *envp[])
{
    while(1)
    {
        int fd= atoi(argv[0]);
        printf("printf get fd is %d\n",fd);
        ssize_t write_ret = write(fd,"execve write",sizeof("execve write"));
        if(write_ret == -1)
        {
            printf("execve write %ld  reason is  %s\n",write_ret,strerror(errno));
        }
        else
       {
           printf("execve write %ld\n",write_ret);
       }


        sleep(2);
    }
    return 0;
}

编译并运行:

gcc -Wall -g cloexec.c -o cloexe

gcc -Wall -g print.c -o print


查看结果

there is 1 param
fd is 3
children pid is 27813 
master write 2  to a.txt 
printf get fd is 3
execve write 13
master write 2  to a.txt 
printf get fd is 3
execve write 13
master write 2  to a.txt 
printf get fd is 3
execve write 13
master write 2  to a.txt 
printf get fd is 3
execve write 13



如果把O_CLOEXEC标志位加上:

重新编译运行

结果为:

there is 1 param
fd is 3
children pid is 27822 
master write 2  to a.txt 
printf get fd is 3
execve write -1  reason is  Bad file descriptor
master write 2  to a.txt 
printf get fd is 3
execve write -1  reason is  Bad file descriptor
master write 2  to a.txt 
printf get fd is 3
execve write -1  reason is  Bad file descriptor


可以看到文件描述符是关闭的

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值