pipe sair do loop

1. pipe sair do loop

???
gokernel

(usa Linux Mint)

Enviado em 09/11/2016 - 09:23h

Olá pessoal !

Como fazer esse código não ficar prezo no loop ?

Testado somente no Windows.


/*
**-------------------------------------------------------------------
**
** PIPE TEST:
**
** ARQUIVO:
** pipe.c
**
** COMPILE:
** gcc pipe.c -o pipe -Wall
**
**-------------------------------------------------------------------
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <io.h>
#include <fcntl.h>

char string[1024], buf[10];
int stdout_saved, i;
int mypipe[2];

int main()
{
stdout_saved = dup (STDOUT_FILENO); // salva

#ifdef __linux__
if (pipe(mypipe)) {
#endif
#ifdef _WIN32
if (_pipe (mypipe, 1024, O_TEXT)) {
#endif
printf ("pipe nao funfa ...\n");
return 0;
}
dup2 (mypipe[1], STDOUT_FILENO); // redireciona para stdout
close (mypipe[1]);

printf("PRIMEIRA LINHA\n");
printf("Segunda LInha\n");
printf("TERCEIRA CASA\n");
printf("CONTINUANDO FINALIZANDO testando\n");
printf("ULTIMA LINHA\n");
fflush (stdout);


//-------------------------------------------
// FICA PRESO AQUI NO LOOP ...
//-------------------------------------------
// Como copiar para o string sem "terminar o pipe" ???
//-------------------------------------------
//
i = 0;
while (read(mypipe[0], buf, 1))
{
string[i++] = buf[0];
}
string[i] = 0;
//-------------------------------------------

dup2 (stdout_saved, STDOUT_FILENO); // normaliza ( stdout ) para testar

/*
//------------------------------------------------------------
// se colocar aqui funciona normal ... nao fica presso no loop
//------------------------------------------------------------
//
i = 0;
while (read(mypipe[0], buf, 1))
{
string[i++] = buf[0];
}
string[i] = 0;
*/

printf("STRING(%s)\n", string);

return 0;

}



Grato !



  


2. Re: pipe sair do loop

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/11/2016 - 12:05h

O comportamento normal -- pelo menos no UNIX -- quando você manda ler de um pipe é que a operação de leitura fique bloqueada enquanto não chegarem todos os bytes solicitados. Por exemplo, se eu mando ler mil bytes, mas o remetente só envia novecentos e noventa e nove, a operação de leitura vai ficar parada esperando pelo byte que falta para completar os mil.

No seu caso, você manda ler de byte em byte, mas faz essa operação em loop. Desse modo, se o remetente enviar um total de cem bytes, as cem primeiras iterações do loop de leitura vão completar imediatamente, mas a centésima primeira vai parar, esperando por mais um byte, mesmo que ele nunca seja enviado pelo transmissor.

A única forma de forçar o sincronismo de um pipe através do próprio pipe é fechar a ponta de envio de dados. Nesse caso, o sistema operacional responde aos eventos de leitura no pipe com uma quantidade de bytes menor do que a solicitada. Uma leitura de tamanho zero implica que a comunicação chegou ao final.

Para contornar o bloqueio em operações de leitura há diversos meios. Dentre eles, lembro agora dos seguintes:

- Usar select() ou poll() para examinar o descritor de leitura, a fim de ver se há bytes disponíveis para leitura antes de disparar a operação de leitura propriamente dita. Ao usar essas funções, você pode inclusive optar por usar um intervalo máximo de espera (timeout) para que cheguem dados pelo canal de comunicação.

- Marcar o descritor de leitura como não-blocante, através de uma chamada a fcntl(). Nesse caso, chamadas a read() num pipe em que a ponta de leitura ainda estiver aberta podem retornar com uma contagem de bytes menor do que a solicitada. No caso de não haver dados disponíveis no momento, o valor de retorno será -1, e errno terá o valor EAGAIN (ou EWOULDBLOCK; dependendo da implementação, os dois nomes podem inclusive ser equivalentes). O fechamento da ponta de escrita continuará sendo indicado por um valor de retorno zero para read().

- Usar alarmes assíncronos ou timers cercando a operação de leitura, de modo que, se ela demorar mais do que o tempo programado, ela seja interrompida. Nesse caso, se read() já tiver recebido alguns bytes, ela pode retornar com uma contagem menor do que a solicitada. Se nenhum byte tiver ainda sido lido, ela o valor de retorno é -1, e o código de erro em errno é EINTR.

Em conjunto com todos os casos acima, mas que também pode servir como quarta alternativa, você deve criar um protocolo de comunicação que lhe possibilite diminuir o esforço com operações de entrada e saída, bem como facilitar a identificação de possíveis pontos favoráveis a uma pausa na leitura.

Por exemplo, se você estabelecer que suas mensagens são orientadas a linha, você poderia se beneficiar das funções da biblioteca de E/S que já fazem operações orientadas a linha, e pode examinar cada linha lida a fim de ver se elas indicar que é o momento de parar de ler. O código abaixo dá uma ideia aproximada disso (não testei o código, mas ele pode ter algumas race conditions, particularmente ).

int read_errno;
unsigned n_lines=0;
char line[1000];
size_t line_len;
char *rc;
FILE *pipe_in;

pipe_in=fdopen(pipe_fd[0], "r");
setvbuf(pipe_in, NULL, _IOLBF, 0); // OPCIONAL: pode melhorar (ou piorar -- não testei) num protocolo orientado a linhas.
while(1){
alarm(5); // Define um timeout de 5 segundos.
errno=0;
rc=fgets(line, sizeof line, pipe_in);
read_errno=errno; // Salvo errno porque a próxima operação pode interferir com ele.
alarm(0); // Desliga alarme após fim da operação de leitura.
if(rc==NULL){
if(read_errno==EINTR)
continue; // Timeout sem dados: repete o loop esperando a chegada de dados.
if(!feof(pipe_in)) // Testa se chegou ao fim de dados (fechamento da ponta de escrita do pipe).
fprintf(stderr, "Erro de leitura ao ler a %dª linha: %s.\n", n_lines+1, strerror(read_errno));
break;
}
line_len=strlen(line);
if(line[line_len-1]!='\n'){
// Linha incompleta: pode ser longa demais, ou pode ser que faltem dados no pipe.
if(line_len+1==sizeof line){
// Dados não cabem na linha. Dá o tratamento que você definir.
}
else{
// Timeout durante a leitura da linha. Você pode querer
// continuar lendo a partir do ponto em que parou, ou pode
// abortar. Você escolhe.
}
}
else{
// Linha completa. Pode tomar decisões de protocolo em função do conteúdo recebido.
++n_lines;
line[line_len-1]='\0';
if(strcmp(line, "abort")==0){
fclose(pipe_in);
break;
}
else if(strncmp(line, "echo ", 5)==0){
puts(line+5);
}
else{
fprintf(stderr, "Comando inválido \"%s\" na linha %u.\n", line, n_lines);
}
}
}



3. Re: pipe sair do loop

???
gokernel

(usa Linux Mint)

Enviado em 09/11/2016 - 12:15h


Caramba !, um monte de texto para assimilar ... estou com fome agora (11:13) ... depois vejo/leio ;).

Grato !







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts