pipe2(...)vs pipe()+ fcntl(...),为什么不同?

时间:2017-02-01 09:42:51

标签: c sockets pipe nonblocking

我正在尝试构建一个可再发行的二进制文件来放置只有libc 2.3的旧NAS。所以pipe2()在那台机器上不可用,但我正在尝试构建的代码有以下几行:

if (pipe2(info_pipe, O_CLOEXEC | O_NONBLOCK) < 0)
    goto info_pipe_err;

我的理解是pipe2()存在的原因是通过采用O_CLOEXEC |来避免竞争条件O_NONBLOCK在开幕时与两步完成比赛。但是在我看的情况下没有线程,所以我想我可能只会替换:

if (pipe(info_pipe) < 0)
    goto info_pipe_err;

int direction; // 0=READ, 1=WRITE
for (direction = 0; direction < 2; ++direction) {
    int oldflags;
    oldflags = fcntl(info_pipe[direction], F_GETFL);
    if (oldflags < 0)
        goto info_pipe_err; 
    if (
        fcntl(info_pipe[direction], F_SETFL, oldflags | O_NONBLOCK | O_CLOEXEC) < 0
    ){
        goto info_pipe_err;
    }
 }

但它似乎不可互换,因为代码不起作用。为什么这不等同?

1 个答案:

答案 0 :(得分:2)

(回答我自己的问题,因为我发现了,只是在这里发帖给后人。)

如果您正在为较旧的系统在较新的编译器上构建二进制文件,那么该运行时可能不知道O_CLOEXEC的值...因为该标志是随pipe2()引入的。如果它知道任何事情,它就知道file template。并且您没有使用FD_CLOEXEC进行设置,而是使用F_SETFL ...这是一个单独的fcntl()调用。

以下替换应该有效:

F_SETFD

如上所述,这没有if (pipe(info_pipe) < 0) goto info_pipe_err; int direction; // 0=READ, 1=WRITE for (direction = 0; direction < 2; ++direction) { int oldflags; oldflags = fcntl(info_pipe[direction], F_GETFL); if (oldflags < 0) goto info_pipe_err; if ( fcntl(info_pipe[direction], F_SETFL, oldflags | O_NONBLOCK) < 0 ){ goto info_pipe_err; } oldflags = fcntl(info_pipe[direction], F_GETFD); if (oldflags < 0) goto info_pipe_err; if ( fcntl(info_pipe[direction], F_SETFD, oldflags | FD_CLOEXEC) < 0 ){ goto info_pipe_err; } } 提供的线程安全方面,允许一次完成所有这些。