As leituras de pipe não são maiores que as do PIPE_BUF atomic?

5

O manual da biblioteca GNU C mencionou brevemente que tanto as leituras quanto as gravações de um pipe são atomic

Reading or writing pipe data is atomic if the size of data written is not greater than PIPE_BUF.

No entanto, as páginas de manual no Linux, como man 7 pipe , não mencionam que as leituras são atômicas e man 2 read declara explicitamente que a leitura pode retornar menos que a quantidade solicitada se a leitura for interrompida por um sinal.

Então, as chamadas de leitura para um canal com o comprimento de leitura em PIPE_BUF são realmente atômicas no Linux?

Em particular, se um único gravador no pipe sempre escrever, por exemplo, um byte de 12 bytes e houver dois leitores simultâneos para o pipe que ler o pipe em 12 bytes, esses leitores obterão exatamente 12 bytes lidos ou um erro como EAGAIN sem possibilidade de obter uma leitura parcial?

Além disso, e sobre o caso em que o escritor escreve por blocos de 12 bytes, mas os leitores simultâneos tentam ler PIPE_BUF/12 pedaços de uma só vez? Uma leitura bem-sucedida sempre retorna o multiplicador exato de 12 bytes ou pode retornar qualquer número de bytes?

    
por Igor Bukanov 22.02.2017 / 09:11

1 resposta

2

Olhando para o código-fonte, a implementação de pipe_read em source/fs/pipe.c mudou bastante no kernel do Linux, mas a partir de uma leitura rápida do código em 2.0.40 , 2.4.37 , 2.6.32 , 3.11 e 4.9 , parece-me que sempre que houve ( ou é, enquanto read está bloqueando) uma gravação do tamanho w e uma leitura do tamanho r com r > w , então read retornará pelo menos w bytes. Então, se você tem pedaços de tamanho fixo (de um tamanho menor que PIPE_BUF ) e sempre faz leituras desse mesmo tamanho, então você está na prática garantido para sempre ler um pedaço inteiro.

Por outro lado, se você tem pedaços de tamanho variável, não há essa garantia. Existe uma garantia de atomicidade apenas no lado da escrita: uma gravação de menos que PIPE_BUF não será cortada por outro gravador. Mas no lado do leitor, se houve e. uma escrita de 10 bytes seguida por uma escrita de 20 bytes, e você depois tenta ler 15 bytes, então você obterá a primeira gravação completa e os primeiros 5 bytes da segunda escrita. A chamada read não pára de ler os dados até que eles precisem bloquear ou o buffer de saída está cheio.

Se você quiser transmitir dados em partes, use um soquete de datagrama em vez de um canal.

    
por 23.02.2017 / 01:29