読者です 読者をやめる 読者になる 読者になる

sysread()でブロックされる

sysread()で子プロセスからパイプで読み取りをしている。
select()で待ってから1バイトずつsysread()しているのだが、読み取るデータが無くなるとsysread()がブロックしてしまう。
読み取るデーがないときはsysread()がブロックせずに0を返してもらいたい。

my $rin = my $win = my $ein = '';
my ($rout, $wout, $eout);
vec($rin, fileno($handle), 1) = 1;
while(my $ns = select($rout=$rin, $wout=$win, $eout=$ein, $timeout)) {
    if ( vec($rout, fileno($handle), 1) )  {
        while(sysread($handle, my $s, 1)) {

        }
    }
}


●sysread()は最低1バイト読み取るまでブロックされると言う情報がある。
Gearmanのやつ#2 - naoyaの日記 - naoyaグループ
http://naoya.g.hatena.ne.jp/naoya/20070929/1191038378

sysread() 関数では部分的な読み取りが可能である。この関数は、リクエストされたデータをすぐに読み取れない場合、その時点で取得できるデータを返す。データがまったくない場合、sysread() 関数は最低でも1バイトを読み取るまでブロックされる。このため、sysread() 関数は、データが不確定なサイズで送信されることが多いネットワーク通信に欠かせない存在である。


●これで解決! ハンドルを非ブロックモードにすればよい。
読み取るべきデータがなければ、sysread()はブロックせずに戻る。

Recipe 7.14. Doing Non-Blocking I/O
http://www.unix.com.ua/orelly/perl/cookbook/ch07_15.htm

use Fcntl;

fcntl(HANDLE, F_GETFL, $flags)
    or die "Couldn't get flags for HANDLE : $!\n";
$flags |= O_NONBLOCK;
fcntl(HANDLE, F_SETFL, $flags)
    or die "Couldn't set flags for HANDLE: $!\n";