J'essaie une implémentation de shell C à partir d'un cours ouvert, mais il y a quelque chose d'intrigant sur le comportement de la mise en mémoire tampon de sortie.Comportement de mise en mémoire tampon de sortie étrange dans C
Le code va comme ceci (notez la ligne où j'utilise pid = waitpid (-1, & r, WNOHANG)):
int
main(void)
{
static char buf[100];
int fd, r;
pid_t pid = 0;
// Read and run input commands.
while(getcmd(buf, sizeof(buf)) >= 0){
if(buf[0] == 'c' && buf[1] == 'd' && buf[2] == ' '){
buf[strlen(buf)-1] = 0; // chop \n
if(chdir(buf+3) < 0)
fprintf(stderr, "cannot cd %s\n", buf+3);
continue;
}
if((pid = fork1()) == 0)
runcmd(parsecmd(buf));
while ((pid = waitpid(-1, &r, WNOHANG)) >= 0) {
if (errno == ECHILD) {
break;
}
}
}
exit(0);
}
La fonction runcmd est comme ceci (notez que dans tuyau de manutention Je crée 2 processus enfants et d'attendre pour eux de mettre fin):
void
runcmd(struct cmd *cmd)
{
int p[2], r;
struct execcmd *ecmd;
struct pipecmd *pcmd;
struct redircmd *rcmd;
if(cmd == 0)
exit(0);
switch(cmd->type){
case ' ':
ecmd = (struct execcmd*)cmd;
if(ecmd->argv[0] == 0) {
exit(0);
}
// Your code here ...
// fprintf(stderr, "starting to run cmd: %s\n", ecmd->argv[0]);
execvp(ecmd->argv[0], ecmd->argv);
fprintf(stderr, "exec error !\n");
exit(-1);
break;
case '>':
case '<':
rcmd = (struct redircmd*)cmd;
// fprintf(stderr, "starting to run <> cmd: %s\n", rcmd->file);
// Your code here ...
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (rcmd->type == '<') {
// input
close(0);
if (open(rcmd->file, O_RDONLY, mode) != 0) {
fprintf(stderr, "Opening file error !\n");
exit(-1);
}
} else {
// output
close(1);
if (open(rcmd->file, O_WRONLY|O_CREAT|O_TRUNC, mode) != 1) {
fprintf(stderr, "Opening file error !\n");
exit(-1);
}
}
runcmd(rcmd->cmd);
break;
case '|':
pcmd = (struct pipecmd*)cmd;
// fprintf(stderr, "starting to run pcmd\n");
// Your code here ...
pipe(p);
if (fork1() == 0) {
// child for read, right side command
close(0);
if (dup(p[0]) != 0) {
fprintf(stderr, "error when dup !\n");
exit(-1);
}
close(p[0]);
close(p[1]);
runcmd(pcmd->right);
fprintf(stderr, "exec error !\n");
}
if (fork1() == 0) {
// left side command for writing
close(1);
if (dup(p[1]) != 1) {
fprintf(stderr, "dup error !\n");
exit(-1);
}
close(p[0]);
close(p[1]);
runcmd(pcmd->left);
fprintf(stderr, "exec error !\n");
}
close(p[0]);
close(p[1]);
int stat;
wait(&stat);
wait(&stat);
break;
default:
fprintf(stderr, "unknown runcmd\n");
exit(-1);
}
exit(0);
}
la chose est étrange, quand j'execute « ls | sort » dans le terminal, je reçois constamment f Sortie uite
6.828$ ls | sort
6.828$ a.out
sh.c
t.sh
Cela indique que, avant la prochaine invite de commande « 6828 $ » est imprimé, la sortie du processus enfant est toujours pas rincée à la borne.
Cependant, si je ne me pid = waitpid (-1, & r, WNOHANG)) et utiliser pid = waitpid (-1, & r, 0)) (ou attente()), la sortie serait normal comme:
6.828$ ls | sort
a.out
sh.c
t.sh
J'ai pensé à la cause du problème depuis longtemps, mais ne suis pas venu avec une raison possible. Quelqu'un peut-il suggérer une raison possible?
Merci beaucoup!