Perl Fcntl 调用 F_SETPIPE_SZ 或 F_GETPIPE_SZ 抛出 "Bad file descriptor"

Perl Fcntl calls to F_SETPIPE_SZ or F_GETPIPE_SZ throws "Bad file descriptor"

背景:

我正在尝试编写一个同时记录 JSONS 的小脚本,如果文件很小,一切正常。但是当文件很大时,进程开始相互覆盖。这个 SO post 有助于指出正确的方向:. Windows seems to have it set to 1024, on linux larger How big is the PIPE_BUFF?

PS: 我在 WSL2 Ubuntu 20.04

问题

我尝试使用 Fcntl constant F_SETPIPE_SZ 设置 PIPE_BUFF 值,但我没有成功:

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Data::Dumper qw(Dumper);
use File::Basename qw(basename dirname);
use File::Spec qw(catfile file_name_is_absolute catdir);
use feature qw(say current_sub);
use Cwd qw(abs_path);
use lib dirname(abs_path [=13=]);
use Fcntl qw(F_SETPIPE_SZ F_GETPIPE_SZ F_GETFL F_GETFD F_SETFL O_NONBLOCK O_WRONLY O_APPEND O_CREAT O_RDWR F_DUPFD F_SETOWN F_GETOWN);

open(my $fileH,">", File::Spec -> catfile(dirname(__FILE__), "blabla.txt"));
#does F_GETFD work?
my $val = fcntl($fileH, F_GETFD, 0);
say $val; #outputs 1, works
#does F_GETFL work?
my $val2 = fcntl($fileH, F_GETFL, 0);
say $val2; #outputs 32769, works
#does F_GETOWN work?
my $val3 = fcntl($fileH, F_GETOWN, 0);
say $val3; #outputs 0 but true, so it works too.
my $pid = +$$;#process id
#does F_SETOWN work?
my $val4 = fcntl($fileH, F_SETOWN, $pid) or die("error: $!");;
say $val4; #outputs 0 but true
#does getting pipe buffer work?
my $val5 = fcntl($fileH, F_GETPIPE_SZ, 0) or die("error: $!"); #"Bad file descriptor"
say $val5; #Use of uninitialized..so $val5 is undef, did not work
#does setting pipe buffer work?
my $val6 = fcntl($fileH, F_SETPIPE_SZ, 1000 * 1000) or die("error: $!"); #"Bad file descriptor"
say $val6; #undef

几个常量,如 F_GETFD 或 F_GETFL 有效,所以我猜 Fcntl 运行正常。

然而 F_SETPIPE_SZ 和其他一些似乎根本不起作用。传递 fcntl fileno($fileH) 而不是 $fileH 会导致“未打开的文件句柄”错误,因此它也不会改变任何内容。

这背后的根本原因是什么?

Linux fcntl() 标志 F_GETPIPE_SZF_SETPIPE_SZ 正如其名称所示,特定于 管道 。您正在尝试将它们与常规文件一起使用,因此失败了。

为清楚起见:

#!/usr/bin/env perl                                                                                                                                                                                                                               
use strict;
use warnings;
use feature qw/say/;
use Fcntl qw/F_GETPIPE_SZ/;

open my $file, ">", "/tmp/foo.txt" or die "Unable to open /tmp/foo.txt: $!\n";
pipe my $reader, my $writer or die "Unable to create pipe: $!\n";

if (my $size = fcntl($file, F_GETPIPE_SZ, 0)) {
    say "filehandle size: $size";
} else {
    say "fcntl of file failed: $!";
}

if (my $size = fcntl($reader, F_GETPIPE_SZ, 0)) {
    say "pipe size: $size";
} else {
    say "fcntl of pipe filed: $!";
}

可能的输出:

fcntl of file failed: Bad file descriptor
pipe size: 65536