O buffer será automaticamente liberado para o disco quando um processo sair?

18

Quando eu redireciono a saída de um comando para um arquivo (por exemplo, echo Hello > file ), será garantido que esse arquivo tenha esses dados logo após o comando sair? Ou ainda há uma janela muito pequena entre as saídas de comando e os dados gravados no arquivo? Gostaria de ler o arquivo logo após o comando sair, mas não quero ler um arquivo vazio.

    
por Eric 25.01.2018 / 13:41

9 respostas

19

Existem várias camadas de buffers / caches envolvidos.

  1. O cache da CPU.

    Os dados são reunidos byte por byte e armazenados no cache da CPU. Se o cache da CPU estiver cheio e os dados não tiverem sido acessados por algum tempo, o bloco contendo nossos dados poderá ser gravado na memória principal. Estes são, na maior parte, ocultos dos programadores de aplicativos.

  2. Os buffers em processo.

    Existe alguma memória reservada no processo em que os dados são coletados, portanto, precisamos fazer o menor número possível de solicitações ao SO, porque isso é comparativamente caro. O processo copia os dados para esses buffers, que novamente podem ser protegidos por caches de CPU, portanto, não há garantia de que os dados são copiados para a memória principal. O aplicativo precisa esvaziar explicitamente esses buffers, por exemplo, usando fclose (3) ou fsync (3). A função exit (3) também faz isso antes que o processo seja finalizado, enquanto a função _exit (2) não , razão pela qual há um grande aviso na página de manual para que essa função o chame. somente se você souber o que está fazendo.

  3. Os buffers do kernel

    O sistema operacional mantém seu próprio cache, para minimizar o número de solicitações que ele precisa enviar aos discos. Esse cache não pertence a nenhum processo em particular, portanto, os dados podem pertencer a processos que já terminaram e, como todos os acessos passam por aqui, o próximo programa verá os dados, se tiver chegado aqui. O kernel gravará esses dados nos discos quando tiver tempo para fazê-lo ou quando solicitado explicitamente.

  4. O cache da unidade

    As próprias unidades de disco também mantêm um cache para acelerar os acessos. Elas são gravadas com bastante rapidez e há um comando para gravar os dados restantes nos caches e informar quando isso estiver concluído, o que o sistema operacional usa no desligamento para garantir que nenhum dado seja deixado sem ser gravado antes de ser desativado.

Para sua aplicação, é suficiente que os dados sejam registrados nos buffers do kernel (os dados reais ainda podem viver em caches de CPU neste momento, e podem não ter sido gravados na memória principal): o processo "echo" termina, o que significa que quaisquer buffers em processo devem ter sido liberados e os dados entregues ao sistema operacional e, quando você inicia um novo processo, é garantido que o SO retornará os mesmos dados quando solicitado.

    
por 25.01.2018 / 16:28
23

Se o aplicativo não tiver caches internos, as alterações serão gravadas imediatamente no arquivo. O mesmo para o seu exemplo. O arquivo é uma entidade lógica na memória que será imediatamente atualizada. Qualquer operação subseqüente no arquivo verá as alterações feitas pelo programa.

No entanto, , isso não significa que a alteração foi gravada no disco físico. As alterações podem permanecer nos caches do sistema de arquivos do sistema operacional ou caches de hardware. Para liberar os buffers do sistema de arquivos, use o comando sync .

I'd like to read the file right after the command exits, but I do not want to read an empty file.

Você não deve se deparar com nenhum problema prático aqui.

    
por 25.01.2018 / 13:47
22

Will buffer be automatically flushed to disk when a process exits?

Em geral, a resposta é não .

Depende do comando. Como as outras respostas mencionam, se o comando não armazena internamente os dados, todos os dados estarão disponíveis quando o comando terminar.

Mas a maioria das bibliotecas de E / S padrão, se não todas, fazem buffer padrão por padrão (até certo ponto), e dão garantias diferentes sobre o fluxo automático de buffers quando o aplicativo é fechado.

C garante que uma saída normal libera os buffers . "Saída normal" significa que exit é chamado - explicitamente ou retornando de main . No entanto, a saída anormal pode contornar essa chamada (e, portanto, deixar buffers sem buffer para trás).

Veja um exemplo simples:

#include <signal.h>
#include <stdio.h>

int main() {
    printf("test");
    raise(SIGABRT);
}

Se você compilar isso e executá-lo, test não será necessariamente escrito em stdout.

Outras linguagens de programação oferecem ainda menos garantias: Java, por exemplo, não não esvazia automaticamente o programa rescisão . Se o buffer de saída contiver uma linha não terminada, pode ser perdido, a menos que System.out.flush() tenha sido chamado explicitamente.

Dito isto, o corpo da sua pergunta faz uma pergunta um pouco diferente: se os dados chegarem ao arquivo , ele deverá fazê-lo imediatamente após o término do comando (sujeito às advertências descritas nas outras respostas ).

    
por 25.01.2018 / 14:47
9

Acho que nenhuma questão aborda esse problema suficientemente ainda:

I'd like to read the file right after the command exits, but I do not want to read an empty file.

Como as outras respostas explicam, um programa que funciona bem libera seus buffers de arquivos internos antes que o processo termine normalmente . Posteriormente, os dados ainda podem permanecer nos buffers de kernel ou de hardware antes de serem gravados no armazenamento persistente. No entanto , a semântica do sistema de arquivos do Linux garante que todos os processos vejam o conteúdo dos arquivos da mesma forma que o kernel faz incluindo buffers internos 1 .

Isto é tipicamente implementado tendo no máximo um buffer no kernel por objeto de arquivo e requerendo que todo o acesso a arquivos passe por este buffer.

  • Se um processo ler um arquivo, o kernel apresentará o conteúdo do buffer ao processo, se a parte do arquivo solicitado estiver no buffer; caso contrário, o kernel buscará os dados do meio de armazenamento subjacente e os colocará no buffer, depois voltará para o passo anterior.

  • Se um processo gravar em um arquivo, os dados serão primeiro colocados dentro do buffer no kernel para esse arquivo. Eventualmente, o conteúdo do buffer será liberado para armazenamento. Nesse meio tempo, o acesso de leitura é satisfeito a partir do mesmo buffer (veja acima).

1 Pelo menos para arquivos regulares, diretórios e links simbólicos. FIFOs e sockets são um assunto diferente, já que seu conteúdo nunca é armazenado persistentemente. Existem alguns casos especiais de arquivos regulares cujo conteúdo depende de quem está perguntando; exemplos são arquivos em procfs e sysfs (pense em /proc/self , que é um link simbólico para o ID do processo do processo lendo o link simbólico).

    
por 25.01.2018 / 17:25
5

Supondo que seu comando seja executado por algum programa usando a biblioteca de tempo de execução C, em algum momento ele deve invocar fclose para fechar o arquivo aberto.

A página man da função fclose C diz:

NOTES Note that fclose() only flushes the user space buffers provided by the C library. To ensure that the data is physically stored on disk the kernel buffers must be flushed too, for example, with sync(2) or fsync(2).

e a página man de fflush tem a mesma nota. A página man para close diz:

A successful close does not guarantee that the data has been successfully saved to disk, as the kernel defers writes. It is not common for a file system to flush the buffers when the stream is closed. If you need to be sure that the data is physically stored use fsync(2). (It will depend on the disk hardware at this point.)

Observe que os dados estão disponíveis para outros processos, mesmo que não estejam sincronizados com a unidade. Talvez isso já seja bom o suficiente para você.

Se você tiver dúvidas, escreva um teste.

    
por 25.01.2018 / 13:50
3

When I redirect a command's output to a file (e.g., echo Hello > file) will that file be guaranteed to have such data right after the command exits?

Sim. O shell abre o arquivo de saída e echo é enviado diretamente para ele. Depois que o comando sai, é feito.

Or is there still a very small window between the command exits and data written to the file?

Se os dados já estão na mídia é outra questão, que só importa se houver uma falha de hardware, ou se você inspecionar a partição ao vivo com algum software forense, ignorando o sistema de arquivos montado.

I'd like to read the file right after the command exits, but I do not want to read an empty file.

Não se preocupe, o kernel mantém apenas uma visão do arquivo, independente da frequência com que ele é aberto.

    
por 26.01.2018 / 21:13
2

Como regra geral, qualquer dado pertencente ao kernel é mantido & limpo pelo kernel, ponto final. Esses dados incluem dados transferidos para a memória do kernel por uma chamada de sistema, como write(2) .

No entanto, se a sua aplicação (por exemplo, a biblioteca C) executar o buffer em top , o kernel obviamente não tem idéia e, portanto, não garante sua limpeza.

Além disso, eu não acredito que haja qualquer garantia de tempo para a limpeza - é, em geral, realizada em um "melhor esforço" (leia: "quando eu tiver um segundo ").

    
por 26.01.2018 / 01:34
2

Or is there still a very small window between the command exits and data written to the file?

Não, não há.

I'd like to read the file right after the command exits, but I do not want to read an empty file.

Você pode ler o conteúdo final do arquivo logo após o comando sair, você nunca estará lendo o arquivo vazio. (Em C e C ++, use as chamadas do sistema wait , waitpid , wait3 ou wait4 para aguardar o programa para sair e só então ler o arquivo.Se você estiver usando um shell, outra linguagem de programação ou uma biblioteca (por exemplo, a chamada de biblioteca C ou a classe Java Process ) provavelmente usa uma dessas chamadas de sistema.)

Como outras respostas e comentários apontaram, você pode acabar lendo um arquivo vazio após a saída do programa se o programa tiver saído sem liberar seus buffers de saída internos (por exemplo, por _exit , aborte ou recebe um sinal fatal, ou porque é um programa em Java que sai normalmente. No entanto, não há nada que você possa fazer sobre isso neste ponto: os dados não-reduzidos são perdidos para sempre, espera adicional não os recupera.

    
por 27.01.2018 / 14:42
0

Sim

Desculpe por talvez adicionar outra resposta supérflua, mas a maioria parece se concentrar no arenque vermelho do título da pergunta. Mas, tanto quanto eu posso dizer, a questão não é sobre buffering, mas isso:

When I redirect a command's output to a file (e.g., echo Hello > file) will that file be guaranteed to have such data right after the command exits?

Sim, incondicionalmente. O uso de ">" que você está descrevendo, junto com "|" e "<", é o modelo de processamento baseado em pipe no qual o mundo Unix e Linux é strongmente baseado. Você encontrará centenas, senão milhares de scripts, dependendo totalmente desse comportamento em todas as instalações do Linux.

Funciona como você deseja por projeto, e se houver a menor chance de uma condição de corrida, ele teria sido corrigido provavelmente décadas atrás.

    
por 28.01.2018 / 09:52