Se você fizer uma chamada read()
do sistema em um pipe, ela será interrompida se não houver nada no pipe, mas caso contrário, retornará imediatamente com o que está lá.
Agora, para o que está lá , com o Linux 4.4 no meu sistema multicore amd64, pelo menos (YMMV com outros sistemas ou outras versões do Linux), se um ou mais processos estiverem atualmente fazendo write()
(ou outra chamada do sistema de escrita) na outra extremidade, possivelmente de mais do que a capacidade do pipe (64KiB por padrão nas versões atuais do Linux), o planejador vai e volta entre esses processos e aquele lendo do canal várias vezes durante essa chamada do sistema read()
e read()
podem retornar muito mais do que a capacidade do canal.
O comando dd
é a interface CLI para a chamada do sistema read
.
dd bs=1G count=1
(note que nem todas as dd
implementações suportam esses G
sufixos) faz um read()
do tamanho 1GiB de stdin (seguido por um write()
no stdout)
Com o GNU dd
, você pode evitar o bloqueio no pipe vazio com iflag=nonblock
. Isso define o pipe no modo non-blocking, mas observe que ele deixa o não bloqueio posteriormente, o que pode não ser desejável. Por exemplo:
(date; sleep 2; date) |
(sleep 1
dd bs=1G count=1 status=none iflag=nonblock
wc -c)
dê:
Mon 23 Jan 22:11:30 GMT 2017
wc: 'standard input': Resource temporarily unavailable
0
Como o pipe se torna não bloqueador para wc
também.
E, como dito anteriormente, com ou sem nonblock
, você pode acabar lendo mais do que caberia no canal:
$ (cat /dev/zero & cat /dev/zero & cat /dev/zero) |
(sleep 1; dd bs=1G count=1) | wc -c
0+1 records in
0+1 records out
545914880 bytes (546 MB, 521 MiB) copied, 0.48251 s, 1.1 GB/s
545914880
(e você obteria números diferentes de uma corrida para a próxima).
Outra abordagem em sistemas que suportam isso é usar FIONREAD
ioctl()
para consultar quantos dados estão no canal antes de fazer a leitura.
perl -e '
require "sys/ioctl.ph";
ioctl(STDIN, &FIONREAD, $n) or die "ioctl: $!\n";
$n = unpack "L", $n;
if ($n) {
sysread STDIN, $text, $n or die "read: $!\n";
print $text
}'
Observe que, como é feito em duas etapas, se outro processo também estiver lendo o canal ao mesmo tempo, ainda poderá acabar bloqueando se esse outro processo esvaziar o canal entre o ioctl()
e o read()
.