I trying to write my program in C with pipes. I have three process: P (father), R (child) and W (child). P and R comunicate beetween first pipes. P and W comunicate beetween second pipes. The child R reading the input file, passing every row to father P using the first pipes. Father P reads the words and check if are palindrome, if the word is palindrome the father send it to child W.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#define DIMBUF 1024
int palindroma(const char *stringa)
{
int len = strlen(stringa);
int j = 0;
for (int i = len - 1; i >= 0; i--)
{
if (stringa[i] == stringa[j])
{
j ;
}
else
return 0;
}
return 1;
}
void child_r(int piper, const char *filename, char tmp[DIMBUF])
{
FILE *w_stream, *file;
if ((w_stream = fdopen(piper, "w")) == NULL)
{
perror("writer piper_rp");
exit(1);
}
printf("Sono il figlio R\n");
if ((file = fopen(filename, "r")) == NULL)
{
perror("apertura file");
exit(1);
}
while (fgets(tmp, DIMBUF, file) != NULL)
{
printf("\tLeggo dal file: %s", tmp);
fputs(tmp, w_stream);
}
fclose(file);
fclose(w_stream);
}
void child_w(int piper, char tmp[DIMBUF])
{
FILE *r_stream;
if ((r_stream = fdopen(piper, "r")) == NULL)
{
perror("reader");
exit(1);
}
while (fgets(tmp, DIMBUF, r_stream) != NULL)
{
printf("\tMessaggio ricevuto: %s\n", tmp);
}
fclose(r_stream);
exit(0);
}
void father(int piper_rp, char tmp[DIMBUF], int piper_pw)
{
FILE *r_stream, *w_stream;
int len;
if ((r_stream = fdopen(piper_rp, "r")) == NULL)
{
perror("reader");
exit(1);
}
if ((w_stream = fdopen(piper_pw, "w")) == NULL)
{
perror("writer piper_pw");
exit(1);
}
while (fgets(tmp, DIMBUF, r_stream) != NULL)
{
len = strlen(tmp);
if (tmp[len - 1] == '\n')
tmp[len - 1] = 0;
int pal = palindroma(tmp);
if (pal)
{
printf("\tMessaggio inviato: %s\n", tmp);
fputs(tmp, w_stream);
}
}
fclose(w_stream);
fclose(r_stream);
}
int main(int argc, char const *argv[])
{
/* code */
int piper_rp[2];
int piper_pw[2];
char tmp[DIMBUF];
const char *filename = argv[1];
if (argc != 2)
{
fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
exit(1);
}
if (pipe(piper_pw) == -1)
{
perror("errore pipe_pw");
exit(1);
}
if (pipe(piper_rp) == -1)
{
perror("errore pipe_rp");
exit(1);
}
if (fork() == 0)
{
close(piper_rp[0]);
child_r(piper_rp[1], filename, tmp);
}
else
{
// padre
sleep(1);
close(piper_rp[1]);
close(piper_pw[0]);
printf("\nSono il padre P\n");
father(piper_rp[0], tmp, piper_pw[1]);
if (fork() == 0)
{
printf("\nSono il figlio W\n");
close(piper_pw[1]);
child_w(piper_pw[0], tmp);
}
else
wait(NULL);
}
return 0;
}
and this is my output:
Sono il figlio R
Leggo dal file: Ciao
Leggo dal file: Mondo
Leggo dal file: Ale
Leggo dal file: emme
Leggo dal file: piip
Leggo dal file: veffev
Leggo dal file: Scatola
Leggo dal file: computer
Leggo dal file: america
Leggo dal file: abba
Leggo dal file: acca
Leggo dal file: cielo
Leggo dal file: lampada
Leggo dal file: effe
Sono il padre P
Messaggio inviato: emme
Messaggio inviato: piip
Messaggio inviato: veffev
Messaggio inviato: abba
Messaggio inviato: acca
Messaggio inviato: effe
Why the child W doesn't have an output ? Why the program never enter to the second fork ?
Please help me
CodePudding user response:
You don't close enough pipe descriptors.
Rule of thumb: If you dup2()
one end of a pipe to standard input or standard output, close both of the original file descriptors from pipe()
as soon as possible. In particular, that means before using any of the exec*()
family of functions. The rule also applies with either dup()
or fcntl()
with F_DUPFD
.
Also, as pointed out by Aconcagua in a comment, you don't fork child W until far too late.
You don't wait for all the children to exit.
I see no merit in passing the tmp
buffer from main()
to each of the process functions — it can be a local variable in each function.
Here is some code that works, I think.
/* SO 7478-4122 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
#define DIMBUF 1024
static int palindroma(const char *stringa)
{
int len = strlen(stringa);
for (int j = 0, i = len - 1; i > j; i--, j )
{
if (stringa[i] != stringa[j])
return 0;
}
return 1;
}
static void child_r(int piper, const char *filename)
{
char tmp[DIMBUF];
FILE *w_stream, *file;
if ((w_stream = fdopen(piper, "w")) == NULL)
{
perror("writer piper_rp");
exit(EXIT_FAILURE);
}
printf("Sono il figlio R (%d)\n", getpid());
if ((file = fopen(filename, "r")) == NULL)
{
perror(filename);
exit(EXIT_FAILURE);
}
while (fgets(tmp, sizeof(tmp), file) != NULL)
{
printf("\tLeggo dal file: %s", tmp);
fputs(tmp, w_stream);
}
fclose(file);
fclose(w_stream);
}
static void child_w(int piper)
{
char tmp[DIMBUF];
FILE *r_stream;
printf("Sono il figlio W (%d)\n", getpid());
if ((r_stream = fdopen(piper, "r")) == NULL)
{
perror("reader");
exit(1);
}
while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
printf("\tMessaggio ricevuto: %s", tmp);
fclose(r_stream);
}
static void father(int piper_rp, int piper_pw)
{
char tmp[DIMBUF];
FILE *r_stream, *w_stream;
if ((r_stream = fdopen(piper_rp, "r")) == NULL)
{
perror("fdopen(piper_rp, \"r\")");
exit(EXIT_FAILURE);
}
if ((w_stream = fdopen(piper_pw, "w")) == NULL)
{
perror("fdopen(piper_pw, \"w\")");
exit(EXIT_FAILURE);
}
while (fgets(tmp, sizeof(tmp), r_stream) != NULL)
{
tmp[strcspn(tmp, "\n")] = '\0';
if (palindroma(tmp))
{
printf("\tMessaggio inviato: %s\n", tmp);
fprintf(w_stream, "%s\n", tmp);
}
}
fclose(w_stream);
fclose(r_stream);
}
int main(int argc, char const *argv[])
{
int piper_rp[2];
int piper_pw[2];
const char *filename = argv[1];
if (argc != 2)
{
fprintf(stderr, "Utilizzo %s file.txt \n ", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(piper_pw) == -1 ||
pipe(piper_rp) == -1)
{
perror("errore pipe_pw");
exit(EXIT_FAILURE);
}
int pid1;
int pid2;
if ((pid1 = fork()) < 0)
{
perror("fork()");
exit(EXIT_FAILURE);
}
else if (pid1 == 0)
{
close(piper_pw[0]);
close(piper_pw[1]);
close(piper_rp[0]);
child_r(piper_rp[1], filename);
exit(21);
}
else if ((pid2 = fork()) < 0)
{
perror("fork()");
exit(EXIT_FAILURE);
}
else if (pid2 == 0)
{
close(piper_rp[0]);
close(piper_rp[1]);
close(piper_pw[1]);
child_w(piper_pw[0]);
exit(32);
}
else
{
close(piper_rp[1]);
close(piper_pw[0]);
printf("\nSono il padre P (%d)\n", getpid());
father(piper_rp[0], piper_pw[1]);
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("Child %d exited with status 0x%.4X\n", corpse, status);
}
return 0;
}
I tested with this input file:
Ciao
Mondo
Ale
emme
piip
veffev
Scatola
computer
america
abba
acca
cielo
lampada
effe
amanaplanacanalpanama
ablewasiereisawelba
When run, the output was:
Sono il padre P (30483)
Sono il figlio R (30484)
Leggo dal file: Ciao
Leggo dal file: Mondo
Leggo dal file: Ale
Leggo dal file: emme
Leggo dal file: piip
Leggo dal file: veffev
Leggo dal file: Scatola
Leggo dal file: computer
Leggo dal file: america
Leggo dal file: abba
Leggo dal file: acca
Leggo dal file: cielo
Leggo dal file: lampada
Leggo dal file: effe
Leggo dal file: amanaplanacanalpanama
Leggo dal file: ablewasiereisawelba
Sono il figlio W (30485)
Messaggio inviato: emme
Messaggio inviato: piip
Messaggio inviato: veffev
Messaggio inviato: abba
Messaggio inviato: acca
Messaggio inviato: effe
Messaggio inviato: amanaplanacanalpanama
Messaggio inviato: ablewasiereisawelba
Messaggio ricevuto: emme
Messaggio ricevuto: piip
Messaggio ricevuto: veffev
Messaggio ricevuto: abba
Messaggio ricevuto: acca
Messaggio ricevuto: effe
Messaggio ricevuto: amanaplanacanalpanama
Messaggio ricevuto: ablewasiereisawelba
Child 30484 exited with status 0x1500
Child 30485 exited with status 0x2000
Note that after stripping the newline to test whether the string is a palindrome, it was necessary to add it when sending the message from the parent to the W child — otherwise, the child gets all the palindromes jammed together in a single line.