Why does program hang on child to parent communication? - c

I am trying to understand why my program hangs. The Parent sends input froma
file it reads to the child program, and the child program will send the result of its computation back to it's parent. However, I have trouble sending the message back through a second pipe. The parent seems to hang when reading from the pipe.
From the other posts, I have read it seems to indicate that the parent should wait for the child to finish by using wait or waitpid (which in my case both of them does not resolve my issue).
I have notice by adding print statement that neither the PARENT or the CHILD finishes.. Could someone please explain to me why this is happening?
Why does this not work?
int main(int argc,char** argv) {
char buffer[1];
int i;
int fd1[2]; int fd2[2];
pipe(fd1); pipe(fd2);
pid_t pid;
// FIRST PROCESS.
// -------------------
pid = fork();
if(pid == 0) {
int cnt;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while(read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "( %s )", buffer);
cnt = cnt + *buffer - 48;
}
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
// PARENT.
// ------------------------
int file = open(argv[1], O_RDONLY);
// READ THE FILE.
while(read(file, buffer, 1) > 0) {
if (48 <= *buffer && *buffer <= 57) {
// PIPE TO CHILD.
write(fd1[1], buffer, 1);
}
}
// WAIT FOR CHILD TO FINISH SENDING BACK.
// int status = 0;
// waitpid(pid, &status, 0);
// THIS BLOCK DOESN'T RESOLVE ANYTHING. IT HANGS AT WAIT OR WAITPID.
// **** THIS IS THE PART WHERE IT DOESN'T WORK.
while(read(fd2[0], buffer, 1) > 0) {
fprintf(stderr, "RESULT : %s", buffer);
}
// CLOSING PIPES
for (i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
close(file);
exit(0);
}

You aren't closing enough file descriptors in the parent soon enough.
Rule of thumb: If you
dup2()
one end of a pipe to standard input or standard output, close both of the
original file descriptors returned by
pipe()
as soon as possible.
In particular, you should close them before using any of the
exec*()
family of functions.
The rule also applies if you duplicate the descriptors with either
dup()
or
fcntl()
with F_DUPFD
Now, your child process is following the RoT perfectly. But the corollary for parent processes is that they need to close the unused ends of the pipe, and they must close the write end of a pipe that they use to signal EOF to the reading end of that pipe. This is where your code fails.
Arguably, before reading the file, the parent process should close the read end of the pipe it uses to write to the child, and it should close the write end of the pipe it uses to read from the child.
Then, after reading the whole of the file, it should close the write end of the pipe to the child, before going into the 'read from child' loop. That loop never terminates because the parent still has the write end of the pipe open, so there's a process that could (but won't) write to the pipe.
Also, since the child writes the bytes of an integer onto a pipe, the parent should read the bytes of an integer. Using char buffer[1]; with a %s format is pointless; you need a null terminator for the string, and a single char buffer can't hold both a null byte and any data.
Along with various other improvements ('0' instead of 48, for example), you might end up with:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char** argv)
{
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
exit(EXIT_FAILURE);
}
int fd1[2];
int fd2[2];
char buffer[1];
pipe(fd1);
pipe(fd2);
pid_t pid = fork();
if (pid == 0) {
int cnt = 0;
dup2(fd1[0], STDIN_FILENO);
dup2(fd2[1], STDOUT_FILENO);
for (int i = 0; i < 2; i++) {
close(fd1[i]);
close(fd2[i]);
}
while (read(STDIN_FILENO, buffer, sizeof(buffer)) > 0) {
fprintf(stderr, "(%c)", buffer[0]); // Changed
cnt = cnt + buffer[0] - '0';
}
putc('\n', stderr); // Aesthetics
write(STDOUT_FILENO, &cnt, sizeof(cnt));
exit(0);
}
int file = open(argv[1], O_RDONLY);
if (file < 0) {
fprintf(stderr, "failed to open file '%s' for reading\n", argv[1]);
exit(EXIT_FAILURE);
}
close(fd1[0]); // Added
close(fd2[1]); // Added
while (read(file, buffer, sizeof(buffer)) > 0) {
if ('0' <= buffer[0] && buffer[0] <= '9') {
write(fd1[1], buffer, sizeof(buffer));
}
}
close(file); // Moved
close(fd1[1]); // Added
// Rewritten
int result;
while (read(fd2[0], &result, sizeof(result)) == sizeof(result)) {
fprintf(stderr, "RESULT : %d\n", result);
}
close(fd2[0]); // Added
// Close loop removed
return 0;
}
If that is stored in file pipe71.c and compiled, I get the following outputs when it is run:
$ ./pipe71 pipe71.c
(2)(0)(1)(2)(2)(2)(1)(1)(2)(0)(0)(2)(1)(0)(2)(2)(1)(0)(2)(1)(2)(0)(0)(0)(0)(0)(1)(0)(1)(1)(0)(2)(1)(0)(0)(0)(0)(9)(1)(1)(1)(1)(2)(0)(2)(0)(0)
RESULT : 49
$ ./pipe71 pipe71
(0)(0)(8)(0)(0)(2)(2)(0)(8)(1)(1)(5)(1)(1)(1)(1)(5)(1)(1)(1)(8)(5)(1)(9)(8)(5)(1)(1)(0)(4)(4)(4)(6)(0)(2)(8)(0)(0)(0)(2)(7)(1)(3)(8)(3)(0)(4)(3)(0)(4)(9)(0)(0)(0)(0)(7)(1)(9)(8)(1)(3)(0)
RESULT : 178
$

Related

Unable to read from a pipe after something is written to it by a child process

I create a function exec_in_child which takes the command arguments, pipe file descriptors (fds), read_flag and write_flag as input. When write_flag is set to 1, the child process should duplicate stdout to fds[1], and then execute the command. When read_flag is set to 1, the child should duplicate the stdin to fds[0] and the execute the command.
Do I have to close one end of the pipe when I'm reading/writing to
the other end?
The code below doesn't work. I'm trying to execute /bin/ls inside a child process, write the stdout to the pipe, and then read
it off in the parent process and print it. I'm not able to read in
the parent process.
Can I read and write to the pipe inside the same process without closing other? This situation arises when I want to child to read
from pipe, execute, and then write to the pipe.
#include <stdio.h> /* printf */
#include <stdlib.h>
#include <string.h> /* strlen, strcpy */
int exec_in_child(char *arguments[], const int temp[], int , int);
int main()
{
ssize_t bytes_read;
char *curr_dir = (char *)malloc(500);
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
char *arguments[] = {"/bin/pwd",0};
exec_in_child(arguments, pipefd, 0, 1);
bytes_read = read(pipefd[0], curr_dir, strlen(curr_dir));
printf("%s = %d\n", "bytes read from pipe" ,(int)bytes_read);
printf("%s: %s\n","character read from the pipe",curr_dir);
return 0;
}
int exec_in_child(char * arguments[], const int fds[], int read_flag, int write_flag) {
pid_t pid;
pid = fork();
if (pid < 0) {
perror("Error: Fork Failed");
}
else if (pid == 0){ /*inside the child process */
if (read_flag == 1) {
dup2(fds[0], 0);
perror("Dup2 stdin");
}
if (write_flag == 1) {
dup2(fds[1], 1);
perror("Dup2 stdout");
}
execv(arguments[0], arguments);
perror("Error in child");
exit(1);
} /* if (pid == 0) */
else {
while(pid != wait(0));
} /* if(pid < 0) */
return 0;
}
I get this result:
hmwk1-skk2142(test) > ./a.out
Dup2 stdout: Success
bytes read from pipe = 0
character read from the pipe:
To answer your questions:
1) You do not need to close either end of the pipe in order to use the other end. However, you generally want to close any end(s) of the pipe you're not using. The biggest reason to do this is that the pipe will only close when all open write file descriptors are closed.
2) Your code isn't working because you're using strlen() improperly. This function calculates the length of a string by searching for the null (0) character. When you malloc() the storage for curr_dir you have no guarantee of what resides there (though it will usually be zeroed, as in this case).
Thus, your call strlen(curr_dir) returns zero, and the read() system call thinks you want to read up to zero bytes of data. Change your read call to the following:
bytes_read = read(pipefd[0], curr_dir, 500);
and your code will work perfectly.
3) You can read and write to any pipe you've got a valid file descriptor to. A single process can absolutely read and write the same pipe.

New to IPC, can't get my pipe to work

Sorry for the length of this post... I've encountered about a zillion problems in this. Up front I'll say I'm a student and my professor is a worthless resource. So, all I want to to do is have producer fork, then the parent producer will count some stuff in a file and send two ints to consumer, which was launched by the child process. I've tested everything, the fork and the file stuff works and I have printf statements all over the place so I know what is being done and where the code is at.
When I added the
if (pipe(pipefd) == -1) {
perror("pipe");
}
it caused my parent to just terminate. It reaches "parent pipe open" but then it dies. I checked with $ ps to see if it was just hung, but it's not there; it just dies. If I take that snippet out, it runs to the end but I presume if that code isn't there, then it's not actually aware that pipefd is a pipe... right?
I did search on this site and found another example of this and followed what he did as well as the answer and mine just refuses to work. I'm pretty sure it's a trivially easy thing to fix but I've run out of ideas of what to try :(
I don't really want to post all my code because it'll be a huge wall of text but I don't want to accidentally cut something out that turns out to be important either.
producer.c
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork, execl */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
#include <string.h> /* strlen */
#include <sys/wait.h> /* wait */
#define SLEEP_TIME 8
int main (int argc, char *argv[]){
//PID
pid_t local_pid;
local_pid = fork();
//Logic to determine if the process running is the parent or the child
if (local_pid == -1) {
/* Error:
* When fork() returns -1, an error happened
* (for example, number of processes reached the limit).
*/
fprintf(stderr, "can't fork, error %d\n", errno);
exit(EXIT_FAILURE);
} else if (local_pid == 0) {
//Child specific code
int child;
char *temp[] = {NULL};
printf("Child PID found\n");
child = execv("./consumer", temp);
_exit(0);
} else {
//Parent specific code
printf("Parent running\n");
//open file
FILE * randStrings;
randStrings = fopen("randStrings.txt", "r");
int file_length;
int num_of_e = 0;
int c; //using this as a char
//until eof
while (feof(randStrings) == 0) {
c = fgetc(randStrings);
//calculate length of file
file_length++;
//count e chars
if (c == 'e') {
num_of_e++;
}
}
//close file
fclose(randStrings);
//send bundle to child
int a[2];
a[0] = num_of_e;
a[1] = file_length;
printf("num of e = %i\n", a[0]);
printf("len = %i\n", a[1]);
//set up parent pipe
int pipefd[2];
if (pipe(pipefd) == -1) {
perror("pipe");
printf("x\n");
}
printf("parent pipe open\n");
close(pipefd[0]); //close the read end
write(pipefd[1], &a[0], sizeof(int));
write(pipefd[1], &a[1], sizeof(int));
close(pipefd[1]);
printf("parent pipe closed\n");
//wait for child to finish running
wait(NULL);
printf("parent out\n");
//terminate
}
}
and consumer.c
#include <stdio.h> /* printf, stderr, fprintf */
#include <sys/types.h> /* pid_t */
#include <unistd.h> /* _exit, fork, execl */
#include <stdlib.h> /* exit */
#include <errno.h> /* errno */
#define SLEEP_TIME 5
int main (int argc, char *argv[]){
sleep(SLEEP_TIME);
printf("Child program launched\n");
//receive bundle
int pipefd[2];
int buf[2];
if (pipe(pipefd) == -1) {
perror("pipe");
printf("child x\n");
}
close(pipefd[1]); //child closes write end
buf[0] = 0;
buf[1] = 0;
/*int i = 0; // i dont like this
while (read(pipefd[0], &buf[i], sizeof(int)) > 0) {
i++;
}*/
printf("child reading pipe\n");
read(pipefd[0], &buf[0], sizeof(int));
read(pipefd[0], &buf[1], sizeof(int));
close(pipefd[0]);
//buf should have the stuff in it
int num_of_e = buf[0];
int file_length = buf[1];
printf("child num of e = %i\n", num_of_e);
printf("child len = %i\n", file_length);
//open file
FILE * resultStrings;
resultStrings = fopen("resultStrings.txt", "w");
for (int i = 0; i < num_of_e; i++) {
//write num_of_e e chars
fputc('e', resultStrings);
}
//or if no e chars, write - chars
if (num_of_e == 0) {
for (int i = 0; i < file_length; i++) {
//write file_length '-' chars
fputc('-', resultStrings);
}
}
//close file
fclose(resultStrings);
printf("child out\n");
}
if you're still here after all that, you deserve a thank you just due to the length of this.
You're doing it wrong. The whole mechanism works because a child process inherits the parent's open file descriptors.
It should go like this:
Open the pipe with pipe(pipefd)
fork()
Parent (producer):
closes the read side (pipefd[0])
writes to the write side (pipefd[1])
Child (consumer):
closes the write side (pipefd[1])
reads from the read side (pipefd[0]) or calls exec
You are opening distinct pipes in both the parent and child process (after you've forked.) It needs to happen before you fork.
Now since you're execing, the new process needs to be aware of read-only pipe. There are a couple ways you could do this:
Pass it the file descriptor number (pipefd[0]) on the command line
dup2(1, fd) it to be the stdin of the newly exec'd process

How to wait till data is written on the other end of pipe

I am developing an application in C.
Parent and child process communicate through pipe.
Before writing to pipe, parent process execute another statements. In sample code, i have used sleep(10) to make delay.
In the child process, it should read the data from the pipe.
But data is not read on the read end of pipe in child process.
int main()
{
int pid;
FILE *fp;
fp = fopen("test.txt","w");
char *buff;
int fd[2];
int count = 0 ;
pipe(fd);
pid = fork();
if(pid == 0)
{
close(fd[1]);
ioctl(fd[0], FIONREAD, &count);
fprintf(fp,"Value of count: %d ",count);
buff = malloc(count);
fprintf(fp,"\n TIME before read: %s",__TIME__);
read(fd[0], buff, count);
fprintf(fp,"\nbuffer: %s\n TIME after read %s", buff, __TIME__);
}
else{
close(fd[0]);
sleep(10); //delay caused by application specific code replaced with sleep
write(fd[1],"THIS is it",10);
}
fclose(fp);
return 0;
}
How to make child process wait till data is written on the other end?
Your pipe is opened in blocking mode, and you do nothing to change that, which is likely what you intended.
However, since the first thing you do is request the size of data waiting on the pipe, then blindly jump into reading that many bytes (which in all likelihood will be zero at the time that code executes since the parent hasn't written anything yet) you don't block, and instead just leave because you requested nothing.
There are a number of ways to do this, including a select-loop. If you would rather block on a read until data is available, then do so on a single byte and fill in the remaining data afterward.
This is by no means an example of how to do this right, but it is a short sample of how you can wait on a single byte, request the read-size of the pipe to get the rest of the data, read it, and continue this until the pipe has no data left and the parent shuts down their end:
I hope you find it helpful.
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main()
{
int pid = 0;
// create pipe pair
int fd[2];
pipe(fd);
pid = fork();
if (pid == 0)
{
// child side
char *buff = NULL;
char byte = 0;
int count = 0;
// close write side. don't need it.
close(fd[1]);
// read at least one byte from the pipe.
while (read(fd[0], &byte, 1) == 1)
{
if (ioctl(fd[0], FIONREAD, &count) != -1)
{
fprintf(stdout,"Child: count = %d\n",count);
// allocate space for the byte we just read + the rest
// of whatever is on the pipe.
buff = malloc(count+1);
buff[0] = byte;
if (read(fd[0], buff+1, count) == count)
fprintf(stdout,"Child: received \"%s\"\n", buff);
free(buff);
}
else
{ // could not read in-size
perror("Failed to read input size.");
}
}
// close our side
close(fd[0]);
fprintf(stdout,"Child: Shutting down.\n");
}
else
{ // close read size. don't need it.
const char msg1[] = "Message From Parent";
const char msg2[] = "Another Message From Parent";
close(fd[0]);
sleep(5); // simulate process wait
fprintf(stdout, "Parent: sending \"%s\"\n", msg1);
write(fd[1], msg1, sizeof(msg1));
sleep(5); // simulate process wait
fprintf(stdout, "Parent: sending \"%s\"\n", msg2);
write(fd[1], msg2, sizeof(msg2));
close(fd[1]);
fprintf(stdout,"Parent: Shutting down.\n");
}
return 0;
}
Output
Parent: sending "Message From Parent"
Child: count = 19
Child: received "Message From Parent"
Parent: sending "Another Message From Parent"
Parent: Shutting down.
Child: count = 27
Child: received "Another Message From Parent"
Child: Shutting down.
I think after
ioctl(fd[0], FIONREAD, &count);
the count is 0.
read(fd[0], buff, count) will get no data.
try
read(fd[0], buff, 10)
The problem is with getting number of bytes written to the pipe. You are getting it right after the fork(). If the read process executes first, it will contain no data (and the count will be zero). If the write process execute first, it will contain some data.
How to make child process wait till data is written on the other end?
Since you opened the pipe in blocking mode, you should read as much data as possible, and not try to get the size of written data.
Here is your modified example that waits for a full message :
#include <stdio.h>
#include <sys/ioctl.h>
int main()
{
int pid;
FILE *fp;
fp = fopen("test.txt","w");
char *buff = malloc(1024);
int fd[2];
int count = 0 ;
pipe(fd);
pid = fork();
if(pid == 0)
{
close(fd[1]);
int i = 0;
while ( i < 10 )
{
fprintf(fp,"\n TIME before read: %s \n",__TIME__);
read(fd[0], buff+i, 1);
++ i;
}
fprintf(fp,"Full message received!\nbuffer: %s\n TIME after read %s\n", buff, __TIME__);
}
else{
close(fd[0]);
sleep(10); //delay caused by application specific code replaced with sleep
write(fd[1],"THIS is it",10);
}
fclose(fp);
return 0;
}

Using pipe to pass integer values between parent and child

I'm a little confused on how to properly use pipe() to pass integer values between two processes.
In my program I first create a pipe, then I fork it. I assume I have "Two" pipes then?
From what I understand, this is my assignment.
My parent goes through a for loop checking an integer value "i" for a certain operation, increases a count variable, and saves value into an array. After each check my parent should pass an integer value, "i" to my child through a pipe. My child then uses that integer value, does some check on the value, and should increase a count variable, and save the result in a [shared?] array. Eventually; the child should return it's final count to the parent, who then prints out the two counts, and the "Shared" array.
-> I'm not sure I need to have a shared array or to save the results at all. I may only need the counts - the homework was ambiguous and I'm awaiting a response from the professor. Also; can I even do a shared array between processes? It sounds like a start of some problem to me.
-> Here are my questions:
One; how do I use pipes for integers? I've only seen them for character arrays and previous answers don't seem to think this is possible or legal..? I'm not sure. There was no resolution that I could find on it.
-> How do I use a unidirectional pipe to pass integers to a child? And have the child return something? I'm not sure how I'm able to... differentiate between the two pipes. I do "know" [or think I know] that I have to close one unused portion of each pipe to avoid "Some vague problem".
Sorry for the dumb questions; I haven't been taught processes (aside from fork) or pipes (at all) yet in this class - so I'm not really sure where to start!
Heres parts of my code - it's not pretty and it doesn't work and I don't expect it to. It's more of a shell placeholder. Once I figure out how to use a pipe - I'd Probably make the code make sense.
int main(void)
{
int fd[2];
pid_t childpid;
pid_t parentpid;
int i;
int threecount = 0;
int fivecount = 0;;
int results [MAXSIZE];
parentpid = getpid(); //Get current process ID number
pipe(fd);
childpid = fork();
if(childpid == 0){
close(fd[0]); //Closing this for some other reason
}
int j = 0;
if(childpid > 0)
close(fd[1]); //Closing this for some reason
if( childpid == -1 )
{
perror("Failed to fork\n");
return 1;
}
if (childpid > 0)
{
for(i = 1; i < MAXSIZE;i++)
{
if(i % 5 == 0)
{
fivecount++;
i = results[j];
j++;
wait(NULL);
}
}
}
else if (childpid == 0)
{
if(i % 3 == 0) //This i here should probably be the i value above, piped to the child
{
threecount++;
i = results[j]; //This should be part of th pipe
j++; //Trying to keep count of that shared array, not really the right way to do it though.
}
}
printf("%d %d \n", fivecount,threecount);
return 0;
}
This is about as lame (and no error checking, btw) a sample as I can muster for using a pipe to send int from a parent to a child process, where the child was launched from fork(). It gets more complicated (obviously) for sending and receiving data, but i can't do everything for you. This just forks and waits for an int (actually, the number of bytes that are used by an int) from the child.
Update: Added send+response two-way communication example after this one. See the second code listing for more information.
Hope it helps.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd[2];
int val = 0;
// create pipe descriptors
pipe(fd);
// fork() returns 0 for child process, child-pid for parent process.
if (fork() != 0)
{
// parent: writing only, so close read-descriptor.
close(fd[0]);
// send the value on the write-descriptor.
val = 100;
write(fd[1], &val, sizeof(val));
printf("Parent(%d) send value: %d\n", getpid(), val);
// close the write descriptor
close(fd[1]);
}
else
{ // child: reading only, so close the write-descriptor
close(fd[1]);
// now read the data (will block)
read(fd[0], &val, sizeof(val));
printf("Child(%d) received value: %d\n", getpid(), val);
// close the read-descriptor
close(fd[0]);
}
return 0;
}
Output:
Parent(5943) send value: 100
Child(5945) received value: 100
Update: Expanded to include send+response using two pipe sets
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
// some macros to make the code more understandable
// regarding which pipe to use to a read/write operation
//
// Parent: reads from P1_READ, writes on P1_WRITE
// Child: reads from P2_READ, writes on P2_WRITE
#define P1_READ 0
#define P2_WRITE 1
#define P2_READ 2
#define P1_WRITE 3
// the total number of pipe *pairs* we need
#define NUM_PIPES 2
int main(int argc, char *argv[])
{
int fd[2*NUM_PIPES];
int val = 0, len, i;
pid_t pid;
// create all the descriptor pairs we need
for (i=0; i<NUM_PIPES; ++i)
{
if (pipe(fd+(i*2)) < 0)
{
perror("Failed to allocate pipes");
exit(EXIT_FAILURE);
}
}
// fork() returns 0 for child process, child-pid for parent process.
if ((pid = fork()) < 0)
{
perror("Failed to fork process");
return EXIT_FAILURE;
}
// if the pid is zero, this is the child process
if (pid == 0)
{
// Child. Start by closing descriptors we
// don't need in this process
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// used for output
pid = getpid();
// wait for parent to send us a value
len = read(fd[P2_READ], &val, sizeof(val));
if (len < 0)
{
perror("Child: Failed to read data from pipe");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Child: Read EOF from pipe");
}
else
{
// report what we received
printf("Child(%d): Received %d\n", pid, val);
// now double it and send it back
val *= 2;
printf("Child(%d): Sending %d back\n", pid, val);
if (write(fd[P2_WRITE], &val, sizeof(val)) < 0)
{
perror("Child: Failed to write response value");
exit(EXIT_FAILURE);
}
}
// finished. close remaining descriptors.
close(fd[P2_READ]);
close(fd[P2_WRITE]);
return EXIT_SUCCESS;
}
// Parent. close unneeded descriptors
close(fd[P2_READ]);
close(fd[P2_WRITE]);
// used for output
pid = getpid();
// send a value to the child
val = 42;
printf("Parent(%d): Sending %d to child\n", pid, val);
if (write(fd[P1_WRITE], &val, sizeof(val)) != sizeof(val))
{
perror("Parent: Failed to send value to child ");
exit(EXIT_FAILURE);
}
// now wait for a response
len = read(fd[P1_READ], &val, sizeof(val));
if (len < 0)
{
perror("Parent: failed to read value from pipe");
exit(EXIT_FAILURE);
}
else if (len == 0)
{
// not an error, but certainly unexpected
fprintf(stderr, "Parent(%d): Read EOF from pipe", pid);
}
else
{
// report what we received
printf("Parent(%d): Received %d\n", pid, val);
}
// close down remaining descriptors
close(fd[P1_READ]);
close(fd[P1_WRITE]);
// wait for child termination
wait(NULL);
return EXIT_SUCCESS;
}
(compile with, e.g., gcc thisfile.c -o test)
Output
Parent(2794): Sending 42 to child
Child(2797): Received 42
Child(2797): Sending 84 back
Parent(2794): Received 84

C Read stdout from multiple exec called from fork

In the code below a process creates one child (fork()) and then the child replaces itself by calling exec(). The stdout of the exec is written in a pipe instead of the shell. Then the parent process reads from the pipe what the exec has written with while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
Can someone tell me how to do the exact same thing as described above but with N number of children processes (who replace themselves with exec as above).
int pipefd[2];
pipe(pipefd);
if (fork() == 0)
{
close(pipefd[0]); // close reading end in the child
dup2(pipefd[1], 1); // send stdout to the pipe
dup2(pipefd[1], 2); // send stderr to the pipe
close(pipefd[1]); // this descriptor is no longer needed
exec(...);
}
else
{
// parent
char buffer[1024];
close(pipefd[1]); // close the write end of the pipe in the parent
while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
{
}
}
I found the answer. I made an array of pipes so that a process does not overwrite the output of another process.
Here is my code. Do you find any mistake?
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#define N 10
int main(int argc, char *argv[]) {
ssize_t readlen;
int pipefd[N][2];
int i;
for (i = 0; i < N; i++) {
pipe(pipefd[i]);
}
int pid = getpid();
for (i = 0; i < N; i++) {
if (fork() == 0) //The parent process will keep looping
{
close(pipefd[i][0]); // close reading end in the child
dup2(pipefd[i][1], 1); // send stdout to the pipe
dup2(pipefd[i][1], 2); // send stderr to the pipe
close(pipefd[i][1]); // this descriptor is no longer needed
char b[50];
sprintf( b, "%d", i);
execl("/bin/echo", "echo", b,NULL);
}
}
if (pid == getpid()) {
// parent
char buffer[1024];
for (i = 0; i < N; i++) {
close(pipefd[i][1]); // close the write end of the pipe in the parent
while ((readlen=read(pipefd[i][0], buffer, sizeof(buffer))) != 0)
{
buffer[readlen] = '\0';
}
printf("%s\n",buffer);
}
}
}
Maybe this code would do the job:
const int N = 10; //Number of child processes
int pipefd[2];
pipe(pipefd);
int i;
for (i = 0; i < N; i++) {
if (fork() == 0) //The parent process will keep looping
{
close(pipefd[0]); // close reading end in the child
dup2(pipefd[1], 1); // send stdout to the pipe
dup2(pipefd[1], 2); // send stderr to the pipe
close(pipefd[1]); // this descriptor is no longer needed
exec(...);
}
}
// parent
char buffer[1024];
close(pipefd[1]); // close the write end of the pipe in the parent
while (read(pipefd[0], buffer, sizeof(buffer)) != 0)
{
}
WARNING: the output will be mixed. If you want all processes to dump data without being mixed, then you should manage to synchronize processes (by means of public locks, for example).
I think you can create named chanel in any place of the file system (like a local socket) and read all received data to parent process. So child processes must write their getted data to this channel. It will be unix-like architecture.

Resources