2011-01-12 3 views
3

J'utilise le code suivant pour rediriger stdout vers un canal, puis lire toutes les données du canal dans un tampon. J'ai 2 problèmes:Comment empêcher le débordement de tampon en C/C++?

premier problème: quand j'envoie une chaîne (après redirection) plus grande que BUFF_SIZE du tuyau, le programme cesse de répondre (blocage ou quelque chose).

deuxième problème: lorsque j'essaie de lire à partir d'un tuyau avant que quelque chose a été envoyé à stdout. Je reçois la même réponse, le programme cesse de répondre - _read commande coincé ...

Le problème est que je ne connais pas la quantité de données qui seront envoyées au tuyau après la redirection.

Le premier problème, je ne sais pas comment gérer et je serai heureux de vous aider. Le deuxième problème que j'ai résolu par une solution de contournement simple, juste après la redirection, j'imprime le caractère d'espace à stdout. mais je suppose que cette solution est la bonne ... un

#include <fcntl.h> 
#include <io.h> 
#include <iostream> 

#define READ 0 
#define WRITE 1 
#define BUFF_SIZE 5 

using namespace std; 

int main() 
{ 

    int stdout_pipe[2]; 
    int saved_stdout; 

    saved_stdout = _dup(_fileno(stdout));   // save stdout 

    if(_pipe(stdout_pipe,BUFF_SIZE, O_TEXT) != 0) // make a pipe 
    {  
    exit(1); 
    } 

    fflush(stdout); 

    if(_dup2(stdout_pipe[1], _fileno(stdout)) != 0) //redirect stdout to the pipe 
    { 
    exit(1); 
    } 

    ios::sync_with_stdio();  
    setvbuf(stdout, NULL, _IONBF, 0); 

    //anything sent to stdout goes now to the pipe 
    //printf(" ");//workaround for the second problem 

    printf("123456");//first problem 

    char buffer[BUFF_SIZE] = {0}; 
    int nOutRead = 0; 
    nOutRead = _read(stdout_pipe[READ], buffer, BUFF_SIZE); //second problem 
    buffer[nOutRead] = '\0'; 

    // reconnect stdout 

    if (_dup2(saved_stdout, _fileno(stdout)) != 0) 
    {   
     exit(1); 
    } 
    ios::sync_with_stdio(); 

    printf("buffer: %s\n", buffer); 
    } 
+0

Pourquoi la taille de votre tampon est-elle si petite? – JimR

+5

Pour éviter le dépassement de la mémoire tampon, n'écrivez pas à la fin de la mémoire tampon. – user562374

+0

le tampon est petit seulement pour cet exemple ...J'utilise un gros buffer mais je cherche une technique pour avoir un buffer moyen et en besoin (quand il est débordé) pour l'agrandir ... – alexpov

Répondre

1

Votre problème est que vous utilisez des appels d'E/S de blocage, alors que les deux extrémités du tube sont connectées au même processus. Si vous ne savez pas combien de données il y aura, il ne s'agit que d'une situation d'impasse.

printf est un appel bloquant, ce qui signifie qu'il ne reviendra pas tant que toutes les données n'auront pas été écrites sur le périphérique de sortie (le canal dans le tuyau est fermé).
_read fonctionne de manière similaire. Il ne retourne que lorsqu'il a une valeur tampon complète de données ou qu'il sait que la fin de l'entrée a été atteinte (ce qui peut être signalé en fermant la fin d'écriture du tuyau).

Les seules façons de contourner ce sont

  • à utiliser non bloquante E/S (ce qui est impossible si vous n'avez pas accès au code qui appelle printf), ou
  • pour assurer la lecture et l'écriture se produisent dans différents processus ou threads, ou
  • pour utiliser un fichier temporaire pour la mise en mémoire tampon, au lieu du tampon d'un canal.
+0

je pense que je comprends, dans mon cas, l'utilisation d'un fichier pour la mise en mémoire tampon est la solution, merci – alexpov

0

Vous devez utiliser non bloquante E/S si vous ne voulez pas lire ou écrire à bloquer dans ce cas.

+0

que voulez-vous dire? Comme je l'ai écrit dans le commentaire précédent: dans mon code, après la redirection, j'appelle une fonction qui fait des calculs et des impressions sur stdout. Je n'ai pas accès au code des fonctions – alexpov

1

Les tuyaux sont unidirectionnels. C'est à dire. vous pouvez écrire dans un tube (x) ou vous pouvez en lire.

Pour simuler un pipeline, essayez ce qui suit (ci-dessous est le C, pas C++):

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc) 
{ 
    int pfds[2]; 

    pipe(pfds); 

    if (!fork()) { 
     close(1);  /* close stdout, check for errors */ 
     dup(pfds[1]); /* make stdout same as pfds[1], dup reuses lowest fd */ 
     close(pfds[0]); /* not needed */ 
     execlp("ls", "ls", NULL); /* or write() in whatever way you want */ 
    } else { 
     close(0);  /* close stdin, check for errors please! */ 
     dup(pfds[0]); /* make stdin same as pfds[0] */ 
     close(pfds[1]); /* not needed on this end */ 
     execlp("wc", "wc", "-l", NULL); /* or read() */ 
    } 

    return 0; 
} 

[modifier] Par ailleurs, votre code ne déborde pas un tampon. Sa seule relation avec le débordement de tampon est que vous lisez dans un tableau alloué statiquement ... si vous read() plus de sizeof buffer éléments, alors vous rencontrerez des problèmes.

+0

j'ai oublié de poster que je veux que mon code fonctionne sous un processus ... mais je pense que j'ai compris le problème et la solution ... merci – alexpov

+0

Peu importe, si vous voulez une communication bidirectionnelle, vous devez utiliser deux tuyaux ... c'est l'essentiel. GL. :) –

+0

que voulez-vous dire 2 tuyaux? – alexpov

Questions connexes