Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/56.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当select将非阻塞fd返回EAGAIN报告为可写时,是否可以将write()写入该fd?_C_Ruby_Macos_Nonblocking - Fatal编程技术网

当select将非阻塞fd返回EAGAIN报告为可写时,是否可以将write()写入该fd?

当select将非阻塞fd返回EAGAIN报告为可写时,是否可以将write()写入该fd?,c,ruby,macos,nonblocking,C,Ruby,Macos,Nonblocking,我正试图追踪OSX10.8.2中的一些奇怪行为。基本上,我打开一个管道,用数据填充它,直到它无法写入。然而,我发现,根据我试图写入的数据块的大小,有时我会从写入调用中获得EAGAIN,即使select声明管道仍然是可写的。下面是一些测试代码: #include <unistd.h> #include <errno.h> #include <stdio.h> #include <fcntl.h> #include <sys/select.h&g

我正试图追踪OSX10.8.2中的一些奇怪行为。基本上,我打开一个管道,用数据填充它,直到它无法写入。然而,我发现,根据我试图写入的数据块的大小,有时我会从写入调用中获得EAGAIN,即使select声明管道仍然是可写的。下面是一些测试代码:

#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/select.h>

#define START 1
#define END 16

int is_writeable(int fd) {
    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;

    fd_set ws;

    FD_ZERO(&ws);
    FD_SET(fd, &ws);

    if(select(fd+1, NULL, &ws, NULL, &timeout) < 0) {
        return -1;
    }

    if(FD_ISSET(fd, &ws))
        return 1;
    else
        return 0;
}

int main(int argc, char *argv[]) {

    int pipes[2];
    int rp, wp, i, errval, fails, tmp;

    char testbuf[END];
    char destbuf[128000];

    for(i = START; i < END; i++) {
        int byte_count = 0;
        printf("%i: ", i);
        fails = 0;

        pipes[0] = 0;
        pipes[1] = 0;

        if(pipe(pipes) < 0) {
            printf("PIPE FAIL\n");
            break;
        }
        rp = pipes[0];
        wp = pipes[1];

        int flags = fcntl(wp, F_GETFL, 0);
        if(fcntl(wp, F_SETFL, flags | O_NONBLOCK) == -1) {
            fails = 4;
        }

        if(is_writeable(wp) != 1) {
            fails = 1;
        }

        while(!fails) {
            // printf(".");
            if(is_writeable(wp) < 1) {
                break;
            }

            tmp = write(wp, testbuf, i);
            //No bytes written, fail
            if(tmp < 0) {
                if(errno == EAGAIN) {
                    if(is_writeable(wp) == 1) {
                        fails = 3;
                        break;
                    }
                } else {
                    fails = 2;
                    perror("During write");

                    break;
                }

            } else {
                byte_count += tmp;
            }
            //Errno is eagain, fail
        }
        printf("byte count %i, ", byte_count);

        if(fails)
            printf("FAIL, %i\n", fails);
        else
            printf("PASS\n");

        if(close(wp) != 0)
            printf("WP CLOSE FAIL\n");
        if(close(rp) != 0)
            printf("RP CLOSE FAIL\n");
    }

}
请注意,故障情况3是写入调用返回-1,但select仍然报告filehandle是可写的

下面是Ruby中显示相同故障的一个较短示例:

(1..10).each do |i|
  passes = true
  begin
    (rp, wp) = IO.pipe
    wp.write_nonblock ("F" * i) while(select [], [wp], [], 0)
  rescue Errno::EAGAIN
    puts "#{i}: FAIL"
    passes = false
  ensure
    rp.close
    wp.close
  end
  puts "#{i}: PASS" if passes
end

我不能确定这是一个bug还是对规范的误解。想法

您正在使用管道。管道有一个有趣的原子写入属性,写入小于管道4096的字节保证是原子的。因此,使用EAGAIN对管道的写入可能会失败,即使可以向管道写入少量字节


我不确定这是否就是您在这里遇到的情况我没有仔细查看,但这种行为在man 7 pipe中有记录。

我不知道这是否有帮助,但在Mac OS X 10.7.5上,我得到了输出抱歉,它必须是一条注释,格式将很糟糕:1:字节计数15873,通过2:字节计数15874,通过3:字节计数15873,通过4:字节计数15876,通过5:字节计数15875,通过6:字节计数15876,通过7:字节计数15876,通过8:字节计数15880,通过9:字节计数15876,通过10:字节计数15880,通过11:字节计数15873,通过12:字节计数15876,通过13:字节计数15873,通过14:字节计数15876,通过15:字节计数15885,通过。select的POSIX规范规定,当对O_NONBLOCK clear的输出函数的调用不会阻塞时,描述符应被视为已准备好写入,函数是否会成功传输数据,但我不确定select如何确定,因为它不知道需要输出多少字节。在我看来,规范应该说。。。调用一个输出函数来传输一个字节,并且O_NONBLOCK clear不会阻塞…我在10.8.2中看到了失败,所以我认为这是山狮中引入的错误。ML还有一个特性,它可以将管道扩展到64kB,这在所有的失败中是很常见的。对于我来说,在64位Linux上也是这样,但是有一个64k的缓冲区@JonathanLeffler@MichaelBurr,或者,规范可以说select在描述符有足够的空间满足描述符的原子性保证时将其描述为就绪,即套接字的空间为1字节,而管道的空间为PIPE_BUF。Linux似乎有这样的解释,因为测试通过了。
(1..10).each do |i|
  passes = true
  begin
    (rp, wp) = IO.pipe
    wp.write_nonblock ("F" * i) while(select [], [wp], [], 0)
  rescue Errno::EAGAIN
    puts "#{i}: FAIL"
    passes = false
  ensure
    rp.close
    wp.close
  end
  puts "#{i}: PASS" if passes
end