Fork parent child communication - c

I need some way for the parent process to communicate with each child separately.
I have some children that need to communicate with the parent separately from the other children.
Is there any way for a parent to have a private communication channel with each child?
Also can a child for example, send to the parent a struct variable?
I'm new to these kind of things so any help is appreciated. Thank you

(I'll just assume we're talking linux here)
As you probably found out, fork() itself will just duplicate the calling process, it does not handle IPC.
From fork manual:
fork() creates a new process by duplicating the calling process.
The new process, referred to as the child, is an exact duplicate of
the calling process, referred to as the parent.
The most common way to handle IPC once you forked() is to use pipes, especially if you want "a private comunication chanel with each child". Here's a typical and easy example of use, similar to the one you can find in the pipe manual (return values are not checked):
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int
main(int argc, char * argv[])
{
int pipefd[2];
pid_t cpid;
char buf;
pipe(pipefd); // create the pipe
cpid = fork(); // duplicate the current process
if (cpid == 0) // if I am the child then
{
close(pipefd[1]); // close the write-end of the pipe, I'm not going to use it
while (read(pipefd[0], &buf, 1) > 0) // read while EOF
write(1, &buf, 1);
write(1, "\n", 1);
close(pipefd[0]); // close the read-end of the pipe
exit(EXIT_SUCCESS);
}
else // if I am the parent then
{
close(pipefd[0]); // close the read-end of the pipe, I'm not going to use it
write(pipefd[1], argv[1], strlen(argv[1])); // send the content of argv[1] to the reader
close(pipefd[1]); // close the write-end of the pipe, thus sending EOF to the reader
wait(NULL); // wait for the child process to exit before I do the same
exit(EXIT_SUCCESS);
}
return 0;
}
The code is pretty self-explanatory:
Parent forks()
Child reads() from the pipe until EOF
Parent writes() to the pipe then closes() it
Datas have been shared, hooray!
From there you can do anything you want; just remember to check your return values and to read dup, pipe, fork, wait... manuals, they will come in handy.
There are also a bunch of other ways to share datas between processes, they migh interest you although they do not meet your "private" requirement:
shared memory "SHM", the name says it all...
sockets, they obviously work as good if used locally
FIFO files which are basically pipes with a name
or even a simple file... (I've even used SIGUSR1/2 signals to send binary datas between processes once... But I wouldn't recommend that haha.)
And probably some more that I'm not thinking about right now.
Good luck.

Related

2 Pipe Problem, why does my parent process keep waiting?

I am trying to make a program containing 2 pipes, and in my program, the child will run first, the parent will run at the end.
The result shows that Child 2, then Child1, and keep pending.
It seems my parent is still waiting for some child process to be finished, but I only got 2 child process in this program~ Please help me :) Thanks!
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/types.h>
int main(void)
{
int pipefd[2];
int pipefd2[2];
int rv= pipe(pipefd);
assert(rv > -1);
int cid = fork();
assert(cid > -1);
int status;
if( cid > 0 ){
//waitpid(cid,NULL,0);
printf("P %d %d\n",getpid(),getppid());
wait(NULL);
printf("Parent \n");
close(0);
dup(pipefd[0]);
close(pipefd[0]);
close(pipefd[1]);
char *const wc_argv[] = {"wc", "-l", NULL};
execvp("wc", wc_argv);
//Parent - Redirect stdout to the write end of the pipe, and execute "ls -l"
}else{
int rv1= pipe(pipefd2);
assert(rv1 > -1);
int cid1 = fork();
assert(cid1 > -1);
if(cid1>0){
printf("C1 %d %d\n",getpid(),getppid());
wait(NULL);
printf("Child1\n");
//Child 1 (parent of child 2)
close(0);
dup(pipefd[0]);
close(1);
dup(pipefd2[1]);
close(pipefd[0]);
close(pipefd[1]);
close(pipefd2[0]);
close(pipefd2[1]);
char *const grep_argv[] = {"grep", "D", NULL};
execvp("grep", grep_argv);
}else{
printf("C2 %d %d\n",getpid(),getppid());
printf("Child2\n");
//Child 2 (child of child 1)
close(1);
dup(pipefd2[1]);
close(pipefd2[0]);
close(pipefd2[1]);
close(pipefd[0]);
close(pipefd[1]);
char *const ls_argv[] = {"ls", "-l", NULL};
execvp("ls", ls_argv);
}
}
}
There are multiple issues with your code. I pointed out some minor matters in comments, but the ones mainly likely to be responsible for the misbehavior you describe are:
Child 1 and the parent both redirect pipefd[0] to their standard inputs. Probably you want child 1 to redirect pipefd2[0] to its standard input instead, but you definitely don't want the two to have the same standard input.
Child 1 redirects its standard output to pipefd2[1], the other end of which pipe will be its standard input once you correct the previous issue. You appear to instead want to redirect to pipefd[1], which presently is not served at all.
Child 1 waits for child 2 before it proceeds. This is non-idiomatic and risky, for you will get a deadlock if child 2 fills the buffer of the second pipe, and therefore blocks before terminating. Pipes are data conduits. Although they do have internal buffers, this should be regarded as an implementation detail. It is incorrect to rely on pipes for buffering. The correct model is that data is consumed from the pipe's read end concurrently with data being written to the pipe's write end.
The parent waits for child 1 before it proceeds. As with child 1's wait, this is risky and non-idiomatic.
Additionally, as #IanAbott remarked in comments, with the way you are arranging the pipes, child 1 waiting for child 2 will reliably produce deadlock. The latter execs a program that will read its standard input to the end, but it will not see EOF on its input until the other ends of the pipe is closed, and that is never closed because child 1 waits on child 2 to finish before it proceeds. I see no necessity for the waits -- neither child 1's nor the parent's -- they could and should just be removed.
OMG!! Thanks ALL
This is my first time posting a question in stack overflow.
I cant believe you guys are so helpful, thank you so much
and i have solved my problem right now.
I can believe I just made a really simple mistake, which is in Child1
close(0);
dup(pipefd2[0]);
close(1);
dup(pipefd[1]);
Original, my program will run parent first, then i want to modify it, then i just thought exchanging the child 2 and parent, everything will be fine, but i forgot to modify the content of child1.
Anyways, you guys are so helpful, and hope you guys stay safe and keep going on our it adventure :)
BTW, I can see there are a lot of recommendations for my code, I will try to digest it :). Thanks all again!!

Read system call blocked sharing a pipe

I'm new in Unix systems programming and I'm struggling to understand file descriptors and pipes. Let's consider this simple code:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main() {
int fd[2], p;
char *m = "123456789\n", c;
pipe(fd);
p = fork();
if (p == 0) {
// child
while(read(fd[0], &c, 1) > 0) write(1, &c, 1);
}
else {
// parent
write(fd[1], m, strlen(m));
close(fd[1]);
wait(NULL);
}
exit (0);
}
When I compile and run the code, it outputs 123456789 but the process never ends unless I issue ^C. Actually, both processes appear as stopped in htop.
If the child closes fd[1] prior to read() then it seems to work OK but I don't understand why. The fd are shared between both processes and the parent closes fd[1] after writing. Why then the child doesn't get the EOF when reading?
Thank you in advance!
Well, first of all your parent process is waiting for the child to terminate in the wait(2) system call, whyle your child is blocked in the pipe to read(2) for another character. Both processes are blocked... so you need to act externally to take them off. The problem is that the child process doesn't close it's writing descriptor of the pipe (and also the parent doesn't close its reading descriptor of the pipe, but this doesn't affect here) Simply the pipe blocks any reader while at least one such writing descriptor is still open. Only when all writing descriptors are closed, the read returns 0 to the reader.
When you did the fork(2) both pipe descriptors (fd[0] and fd[1]) were dup()ed on the child process, so you have a pipe with two open file descriptors (one in the parent, one in the child) for writing, and two open descriptors (again, one in the parent, one in the child) for reading, so as one writer remains with the pipe open for writing (the child process in this case) the read made by the child still blocks. The kernel cannot detect this as an anomaly, because the child could still write on the pipe if another thread (or a signal handler) should want to.
By the way, I'm going to comment some things you made bad in your code:
first is that you consider only two cases from fork() for the parent, and for the child, but if the fork fails, it will return -1 and you'll have a parent process writing on a pipe with no reading process, so probably it should block (as I say, this is not your case, but it is an error either) You have always to check for errors from system calls, and don't assume your fork() call is never to fail (think that -1 is considered != 0 and so it falls through the parent's code). There's only one system call that you can execute without checking it for errors, and it is close(2) (although there's much controversy on this)
This same happens with read() and write(). A better solution to your problem would be to have used a larger buffer (not just one char, to reduce the number of system calls made by your program and so speed it up) and use the return value of read() as a parameter on the write() call.
Your program should (it does on my system, indeed) work with just inserting the following line:
close(fd[1]);
just before the while loop in the child code, as shown here:
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
int main() {
int fd[2], p;
char *m = "123456789\n", c;
pipe(fd);
p = fork();
if (p == 0) {
// child
close(fd[1]); // <--- this close is fundamental for the pipe to work properly.
while(read(fd[0], &c, 1) > 0) write(1, &c, 1);
}
else if (p > 0) {
// parent
// another close(fd[0]); should be included here
write(fd[1], m, strlen(m));
close(fd[1]);
wait(NULL);
} else {
// include error processing for fork() here
}
exit (0);
}
If the child closes fd[1] prior to read() then it seems to work OK but I don't understand why.
That's what you need to do. There's not much more to it than that. A read from the read end of a pipe won't return 0 (signaling EOF) until the kernel is sure that nothing will ever write to the write end of that pipe again, and as long as it's still open anywhere, including the process doing the reading, it can't be sure of that.

Feeding stdout to a child process which will execv() sort

I am trying to find out how I can send output of one process into a child process. I have gone down a journey learning of file descriptors and pipes. I think I am almost there but am missing a key component.
This is what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int fd[2];
pid_t sort_pid;
/* Create the pipe */
if(pipe(fd) == -1) {
fprintf(stderr, "Pipe failed\n");
exit(EXIT_FAILURE);
}
/* create child process that will sort */
sort_pid = fork();
if(sort_pid < 0) { // failed to fork
fprintf(stderr, "Child Fork failed\n");
exit(EXIT_FAILURE);
}
else if(sort_pid == 0) { // child process
close(0); // close stdin
dup2(fd[0], 0); // make stdin same as fd[0]
close(fd[1]); // don't need this end of the pipe
execlp("D:/Cygwin/bin/sort", "sort", NULL);
}
else { // parent process
close(1); // close stdout
dup2(fd[1], 1); // make stdout same as fd[1]
close(fd[0]); // don't need this end of the pipe
printf("Hello\n");
printf("Bye\n");
printf("Hi\n");
printf("G'day\n");
printf("It Works!\n");
wait(NULL);
}
return EXIT_SUCCESS;
}
This doesn't work, as it seems to go into an endless loop or something. I tried combinations of the wait() but that doesnt help either.
I am doing this to learn how to apply this idea in my actual program. In my actual program I read files, parse them line by line and save the processed data to a static array of structs. I want to be able to then generate output based on these results and use the fork() and execv() syscalls to sort the output.
This is ultimately for a project in uni.
These are similar examples which I dissected to get to the stage I am at so far:
pipe() and fork() in c
How to call UNIX sort command on data in pipe
Using dup,pipe,fifo to communicate with the child process
Furthermore I read the manual pages on the relevant syscalls to try and understand them. I will admit my knowledge of pipes and using them is still basically nothing, as this is my first every try with them.
Any help is appreciated, even further sources of information I could look into myself. I seem to have exhausted most of the useful stuff a google search give me.
sort will read until it encounters end-of-file. You therefore have to close the write-end of the pipe if you want it to complete. Because of the dup2, you have two copies of the open file description, so you need
close(fd[1]); anytime after the call to dup2
close(1); after you're done writing to (the new) stdout
Make sure to fflush(stdout) before the second of these to ensure that all your data actually made it into the pipe.
(This is a simple example of a deadlock: sort is waiting on the pipe to close, which will happen when the parent exits. But the parent won't exit until it finishes waiting on the child to exit…)

Trouble with pipes, dup, close and exec in C

Well. I kinda understand how pipes work and why is dup/dup2 used before an exec in any child process.
But I need help with the 'close(int fd)' thing.
To make it clear I would like to ask you for any pseudocode or any C code example which does the following:
Parent gets a fd from a file using open().
Parent creates a child which execs to another program which reads data from the open() func fd used before and writes the output in a pipe. (So parent should wait it to end before continuing).
Same parent then creates another child which is going to exec and read from that write end of the pipe created before and write the output in the stdo.
Is it even posible to do this with only one pipe?
The tricky thing here for me is not creating the pipe and redirecting channels with dup2 and stuff, it is knowing where and when to close() all the fd channels.
If you could explain me how to do a thing like that and when and where to close the channels with an example I think I would definetly understand it all.
Thanks a lot guys.
Below is a complete example. WhozCraig already told that there's no need for parent to wait for child 1 to end before continuing, since child 2 has to read the pipe until EOF. (On the contrary, the parent must not wait, because the pipe buffer might not be large enough to hold all the file data.) Of course there's only one pipe needed, where child 1 writes to one end and child 2 reads from the other. And for that no dup is needed.
When and where does the parent have to close the pipe channels?
The parent may close the pipe ends as soon as it doesn't need them any longer, provided that a child which needs a pipe end has it open, i. e. in our case, the parent may close (its descriptor of) the write end after child 1 has been forked, and the parent may close the read end after child 2 has been forked, since the children inherit the pipe descriptors, and they remain usable until the children close them at exit.
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
main(int argc, char *argv[])
{
if (argc <= 1) return 1;
int fd = open(argv[1], O_RDONLY); // Parent gets a fd from a file.
if (fd < 0) return perror(argv[1]), 1;
int pipefd[2];
if (pipe(pipefd) < 0) return perror("pipe"), 1;
char in[8], out[8];
sprintf(in, "FD:%d", fd); // reads data from the open() func fd
sprintf(out, "FD:%d", pipefd[1]); // writes the output in a pipe
switch (fork())
{ // Parent creates a child which execs to another program, e. g. "socat"
case -1: return perror("fork 1"), 1;
case 0: execlp("socat", "socat", "-u", in, out, NULL);
return perror("execlp 1"), 1;
}
close(pipefd[1]); // parent may close write end, since child has it open
sprintf(in, "FD:%d", pipefd[0]); // read from the pipe created before
sprintf(out, "FD:%d", 1); // write the output in the stdo
switch (fork())
{ // Same parent then creates another child which is going to exec
case -1: return perror("fork 2"), 1;
case 0: execlp("socat", "socat", "-u", in, out, NULL);
return perror("execlp 2"), 1;
}
close(pipefd[0]); // parent may close read end, since child has it open
}

c - continously communicate between two child processes using pipes

Just started learning about pipes (IPC in general). After I went through some man pages, websites and few SO questions like this, This and few others. I got to know the basic and I see that this communication is done only once, i.e., parent writes to child and child reads it or parent and child reads and writes to each other just once and then the pipe closes.
What I want is keep this communication between the processes without the pipe closing, i.e.,
say, my program has 2 child processes where 1st child process is running something in a while loop and the 2nd is running a timer continuously. At certain intervals, my 2nd process sends some 'signal' to 1st child and my 1st stops and prints something at that instant and restarts again for next timer stop. (<-This I have done using threads)
This is the program that I tried just as a sample. But I'm not able to keep the communication continuous.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int fd[2], nbytes, count = 5;
pid_t childpid;
char string[] = "Hello, world!\n";
char readbuffer[80];
if((childpid = fork()) == -1)
{
perror("fork");
exit(1);
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
/* Send "string" through the output side of pipe */
while(count--)
{
pipe(fd);
close(fd[0]);
write(fd[1], string, (strlen(string)+1));
close(fd[1]);
}
exit(0);
}
else
{
/* Parent process closes up output side of pipe */
while(count--)
{
pipe(fd);
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s\n", readbuffer);
close(fd[0]);
close(fd[1]);
}
}
int status;
waitpid(getppid(), &status, 0);
printf("Done!\n");
return(0);
}
From those example, I inferred that the pipe get's closed after each send/read.
I tried opening new pipe every time, still I could't get it.
Can anyone please help me what am I missing or what should I do?
Right now both the parent and child creates their own pair of pipes, that the other process have no knowledge about.
The pipe should be created in the parent process before the fork.
Also, you close the reading/writing ends of the pipe in the loops, when you should close them after the loop, when all the communication has been done.
And a small unrelated issue...
In the reader you should really loop while read doesn't return 0 (then the write-end of the pipe is closed) or -1 (if there's an error).
It would be great if you use the shared memory approach. In this approach the parent will allocate a memory area which will be shared among all the processes. Use locks to secure your resource i.e. shared memory. You can also visit this answer which details what is the concept behind. Also remember that in shared memory approach the communication can be many-to-many. But in case of pipes it is one-to-one.
Cheers,
K.
Infoginx.com

Resources