Eu queria lançar um executável de um processo pai. Esperar até que o processo termine, então ler de volta o que ele escreveu no stdout. Acontece que você não pode esperar o programa terminar e então ler o fluxo FILE*, porque esperar que ele termine significa chamar pclose(FILE*) e nesse ponto o fluxo de arquivo é destruído. Na documentação do Windows, diz para fazer isso :
char psBuffer[128];
FILE* pPipe;
/* Run DIR so that it writes its output to a pipe. Open this
* pipe with read text attribute so that we can read it
* like a text file.
*/
if ((pPipe = _popen("dir *.c /on /p", "rt")) == NULL)
{
exit(1);
}
/* Read pipe until end of file, or an error occurs. */
while (fgets(psBuffer, 128, pPipe))
{
puts(psBuffer);
}
int endOfFileVal = feof(pPipe);
int closeReturnVal = _pclose(pPipe);
if (endOfFileVal)
{
printf("\nProcess returned %d\n", closeReturnVal);
}
else
{
printf("Error: Failed to read the pipe to the end.\n");
}
Ele está abrindo o pipe e, em seguida, lendo imediatamente do fluxo. Não é o caso de que é provável que ele leia o fluxo e ele estará vazio ou no fim do arquivo, já que a leitura é executada imediatamente após iniciar o processo filho? Por que isso é válido?
Mais ou menos. A chamada
pclose()
espera que um processo filho iniciado viapopen()
termine, e esta é a única maneira padrão de obter o status de saída do filho. Tendo chamadopclose()
, não é mais possível ler do fluxo que foi fechado.Mas se a criança não fechar seu stdout antes de terminar -- e a maioria não fecha -- então o pai pode detectar EOF no fluxo associado como um proxy para término, antes de chamar
pclose()
. Isso é natural para um pai que quer ler a saída da criança até o fim. E compopen()
, o pai quase sempre quer fazer isso, porque mesmo que não esteja interessado nos dados em si, ele deve drenar o pipe para garantir que a criança continue a ter espaço para escrever. Pipes têm capacidade limitada, geralmente medida em quilobytes, e se um processo tentar escrever quando não houver espaço suficiente disponível, ele bloqueará até que possa concluir sua escrita * (caso usual) ou falhará de alguma maneira idiossincrática.Então não, você não pode esperar pelo programa e então ler sua saída do fluxo, mas geralmente você pode esperar o programa terminar lendo sua saída do fluxo. Uma vez que você detecta EOF no fluxo, você chama
pclose()
para recuperar o status de saída e limpar, além disso, isso te cobre caso o filho feche sua saída padrão mais cedo.Vazio? Bem possível. Mas para um pipe, isso não é a mesma coisa que estar no fim do arquivo. EOF não ocorre na extremidade de leitura de um pipe até que a extremidade de gravação tenha sido fechada e todos os dados tenham sido lidos dele.
As funções stdio bloqueiam até que transfiram a quantidade de dados que foram especificadas para fazer.
fgets()
em particular, lerá até preencher o buffer fornecido, lerá e transferirá uma nova linha lógica ou atingirá EOF. Que ele pode ter que esperar antes que haja algo para transferir, e que ele pode ter que esperar periodicamente novamente antes de concluir sua transferência, é apenas normal.* O que significa completar uma gravação depende da função que executa a gravação. Para as funções stdio, isso significa gravar todos os bytes especificados, mas há outras funções de E/S para as quais esse não é necessariamente o caso.