I have an app that spawns a child process. That child process outputs information about what it's doing by printing to stdout. The parent process does the same (i.e. prints to stdout).
In the child process I can write to stdout with some text prepended, but I have to add that to every single location I print across many source files.
I thought it might be smarter to have the parent process prepend output from the child process that it forks/exec's. I don't want to redirect the output because seeing the output inline with the parent process is beneficial. How do I do this? I'm using fork/exec in the parent.
Do I have to read the output and prepend each line manually or is there a simpler approach?
Update:
Thanks to Barmar. Here is how I'm doing it. I also could read byte by byte in the parent process from the pipe until line end. But I chose not to use that approach for reasons of complexity in my single threaded lua+C app.
// Crude example of output filtering using sed to
// prepend child process output text
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <libgen.h>
#include <string.h>
pid_t spawn(int fd[2], const char* path)
{
printf("Create child\n");
pid_t pid = fork();
switch(pid){
case -1:
printf("Create process failed");
return -1;
case 0:
dup2(fd[1], STDOUT_FILENO);
close(fd[0]);
close(fd[1]);
execl(path, path, NULL);
return 0;
default:
return pid;
}
}
pid_t spawnOutputFilter(int fd[2])
{
printf("Create sed\n");
pid_t pid = fork();
switch(pid){
case -1:
printf("Create sed failed");
return -1;
case 0:
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execlp("sed", "sed", "s/^/Engine: /", (char *)NULL);
return -1;
default:
return pid;
}
}
int main(int argc, char* argv[])
{
if (argc > 1){
int options;
int fd[2];
pipe(fd);
pid_t pid = spawn(fd, argv[1]);
pid_t sed_pid = spawnOutputFilter(fd);
close(fd[0]);
close(fd[1]);
waitpid(pid, NULL, 0);
waitpid(sed_pid, NULL, 0);
}
return 0;
}
You could create a second child process that performs
execlp("sed", "sed", "s/^/PREFIX: /", (char *)NULL);
Connect the first child's stdout to this process's stdin with a pipe.
I thought it might be smarter to have the parent process prepend output from the child process.
I guess it depends on how you judge "smart". It might be simpler to just make the child prepend the desired text to its outputs.
I don't want to redirect the output because seeing the output inline with the parent process is beneficial. What's the best way to do this?
When two processes share an open file, both access it independently, regardless of the nature of the relationship between those processes. Thus, if your child inherits the parent's stdout, the parent has no mechanism even to notice that the child is sending output, much less to modify that output.
If you want the parent to handle this, you would need to pass the child's output through the parent. You could do that by creating a pipe, and associating the child's stdout with the write end of that pipe. The parent would then need to monitor the read end, and forward suitably-modified outputs to its own stdout. The parent would probably want to create a separate thread for that purpose.
Additionally, if the child sometimes produces multi-line outputs that you want prefixed as a group, rather than per-line, then you'd probably need to build and use some kind of protocol for demarcating message boundaries, which would make the whole parent-moderation idea pretty pointless.
Couldn't you define #define printf(a) printf("your text:" a).
Other alternative I can think of is using dup
You open the same log file in your child process and dup your stdout to new file descriptor.
Related
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…)
i have run this code and found out that the parent process reads first then child process writes. i want to know why this is happening? Additionally i also want to know how can i use two pipes in this program.i just want the concept, any code will be appreciated.Thanks
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
main()
{
int fd[2];
pid_t childpid;
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
}
if(childpid == 0)
{
/* Child process closes up input side of pipe */
close(fd[0]);
printf("\nChild writes\n\n");
}
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
printf("parent reads\n\n");
}
return 0;
}
For you queries :-
The parent process reads first then child process writes. i want to know why this is happening?
After fork() both process work independently, so which process will be scheduled first, it's depend on scheduler.
How can i use two pipes in this program?
open two pipe, one for parents and one for child process. because pipe are unidirectional.
int fd[2];
int fd1[2];
parents will write on fd[1] child will read from fd[0]
child will write on fd1[1] parents will read from fd1[0]
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
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.
I am trying to pass tokens through pipes and execvp... However my problem is that 1st and 2nd child processes receive the same tokens... and what can be done if there is a third or more tokens?
int pipedes[2];
pipe(pipedes);
pid_t pid = fork();
if (pid == 0) {
dup2(filedes[1], 1);
execvp(argv[0], argv);
} else {
close(pipedes[1]);
}
pid = fork();
if (pid == 0) {
dup2(pipedes[0], 0);
execvp(arg[0], argv);
}
wait(&pid);
and tokens
strtok(line, "|");
pipe(line);
while (1) {
line= strtok(NULL, "|");
pipe(line);
}
This line:
pipe(line);
is nonsense. It creates two new file descriptors and overwrites the first 2 x sizeof(int) bytes of line with them. Your producer process should be writing the tokens to stdout and your consumer process should read them from stdin.
By the way, your child processes appear to execute the same executable as the parent with exactly the same arguments. How does each one know whether it is the producer or consumer?
If you want to have two different child executing the same executable, but using two different commands, you will need to setup two different pipes for each child process. Your process for setting up the pipes is also incorrect since you allow the child to leave a pipe open.
#include <sys/wait.h>
#include <unistd.h>
#include <
int pipedes_child_1[2];
int pipedes_child_2[2];
pipe(pipedes_child_1);
pid_t child = fork();
if (!child)
{
dup2(pipedes_child_1[0], 0);
close(pipedes_child_1[1]); //without this, child with hang on read()
execvp(argv[0], argv);
}
else
{
close(pipedes_child_1[0];
}
pipe(pipedes_child_2);
child = fork();
if (!child)
{
dup2(pipedes_child_2[0], 0);
close(pipe_des_child_2[1]); //without this, child with hang on read()
execvp(argv[0], argv);
}
else
{
close(pipedes_child_2[0]);
}
//...write tokens to each child via pipedes_child_X[1];
//wait for all the children
int return_val = 0;
while(wait(&return_val) > 0 || errno != EINTR);
Keep in mind, that since you are calling execvp(argv[0], argv), you are actually going to make an infinitely recursive "fan" of processes since you're just recalling the current process with the current arguments ... I don't think that's what you're wanting. To prevent that, let's say you specify the child processes as arguments to the main parent executable, and pass those values as the programs to launch when calling one of the exec family of functions. So for instance:
//child_1 executable that will take no arguments and read from the pipe
execlp(argv[1], argv[1], (char*)0);
//child_2 executable that will take no arguments and read from the pipe
execlp(argv[2], argv[2], (char*)0);