Here's what I'd like to do:
I've tried to make a program that creates parent with two children, parent creates unnamed pipe, writes into it and the children are supposed to read from it (per 1 byte) and then output the results in two different terminal windows. What I do not know is how to synchronise them.
I get something like this in one terminal window: Nejke aa
and in the second: adt
I want: Nejake data
I tried searching on the internet, but I'm asking anyway.
Any help is greatly appreciated.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
/* declare our procedures */
void runchild1(int pfd[]);
void runchild2(int pfd[]);
/* some data to write and read from pipe */
const char some_data[] = "Nejake data" ;
int main(int argc, char **argv)
{
int pid, status; //PID for debugging
int fd[2]; //file descriptors for the pipe
/* let create some pipe */
pipe(fd);
/* supposed to run two children of the process */
runchild1(fd);
runchild2(fd);
/* this is important! close both file descriptors on the pipe */
close(fd[0]); close(fd[1]);
/* pick up all the dead children */
while ((pid = wait(&status)) != -1)
fprintf(stderr, "process %d exits with %d\n", pid, WEXITSTATUS(status));
exit(0);
}
void runchild1(int pfd[]) /* run the first child */
{
int pid; /* you may want to print it for debugging */
int data_processed; /* store data */
int des; /* descriptor for open files */
char buffer; /* buffer for reading byte of data */
switch (pid = fork()) {
case 0: /* child reads from the pipe */
close(pfd[1]); /* this process don't need the other end */
while ((data_processed = read(pfd[0],&buffer,1)) > 0) {
printf("Proces %d, data citane po bajte: %c\n",getpid(),buffer);
des = open("/dev/ttys001",O_RDWR);
write(des, &buffer,1);
}
exit(0);
default: /* parent writes to the pipe */
/* write some data for children to read */
data_processed = write(pfd[1], some_data, strlen(some_data));
printf("Zapis %d bytov cez nepomenovanu ruru:\n", data_processed);
printf("Zapisane: %s\n",some_data);
printf("Som rodic dvoch deti: %d\n",getpid());
break;
case -1:
perror("fork");
exit(1);
}
}
void runchild2(int pfd[]) /* run the second child */
{
int pid;
int data_processed;
int des;
char buffer;
switch (pid = fork()) {
case 0: /* child */
close(pfd[1]); /* this process doesn't need the other end */
while ((data_processed = read(pfd[0],&buffer,1)) > 0) {
printf("Proces %d, data citane po bajte: %c\n",getpid(),buffer);
des = open("/dev/ttys002",O_RDWR);
write(des, &buffer,1);
}
exit(0);
default: /* parent does nothing */
break;
case -1:
perror("fork");
exit(1);
}
}
If the two children both need to see the same data, you'll need two pipes, one per child, and the parent must write each message twice, once on each pipe.
Alternatively, you could run the tee command with process substitution, or you can look up (try looking up) the program pee (process/pipe variant of tee) — or you can follow links from this Stack Overflow answer. Your program will have one pipe, but the children will each end up with their own pipe.
Unix pipe is FIFO. One input, one output. Nothing like two outputs from one pipe. Your cheats are: System V IPC keyword and ipcs command.
Related
I want to create a IPC c program to create one parent and two child's processes. My code is:
#include <stdio.h>
void main()
{
int pid, status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}
I want to show you an other code snippet to create one parent and two child process. This is what I am looking for. Now I want to write shell script for IPC, first take look of this code.
Note: there is an other code with same logic but different process names UP, uc1, uc2 e.g in this way we have two parent VP and UC and there childs vp1 vp2 and uc1 uc2.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_BUF 1024
int main(){
int mypipe_c1[2];
int ret_c1;
char buf_c1[6];
ret_c1 =pipe(mypipe_c1);
int mypipe_c2[2];
int ret_c2;
char buf_c2[6];
ret_c2 =pipe(mypipe_c2);
if(ret_c1 == -1)
{
perror("pipe");
exit(1);
}
pid_t vc1;
pid_t vc2;
vc1 = fork ();
if (vc1 == 0)
{
read(mypipe_c1[0], buf_c1 , 37);
printf("PIPE1 :%s\n", buf_c1);
printf (" vc1 : I'm the child! My pid is (%d)\n", getpid ());
close(ret_c1);
int fd;
char * fifo1 = "/tmp/fifo1";
char buf[MAX_BUF];
/* open, read, and display the message from the FIFO */
fd = open(fifo1, O_RDONLY);
read(fd, buf, MAX_BUF);
printf("FIFO1: %s\n", buf);
close(fd);
exit(0);
}
if(vc1 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
vc2 = fork ();
if (vc2 == 0)
{
printf ("vc2 : I'm the child! My pid is (%d)\n", getpid ());
read(mypipe_c2[0], buf_c2 , 37);
printf("PIPE2 %s\n", buf_c2);
int fd;
char * fifo2 = "/tmp/fifo2";
/* create the FIFO (named pipe) */
mkfifo(fifo2, 0666);
/* write "Hi" to the FIFO */
fd = open(fifo2, O_WRONLY);
write(fd, " assignment VU 2 ", sizeof(" assignment VU 2 "));
close(fd);
/* remove the FIFO */
unlink(fifo2);
exit(0);
}
else if (vc2 < 0)
{
perror ("Ouch! Unable to fork() child process!\n");
exit (1);
}
printf ("I'm the parent! My pid is (%d)!\n",getpid());
write(mypipe_c1[1], "I am going to close you carry on UC1 \n", 37);
write(mypipe_c2[1], "I am going to close you carry on UC2 \n", 37);
exit(0);
}
Now I want shell script such that VP and UP should be started when users types … script.sh start VP or UP. vc1, vc2, uc1,uc2 should be stoppable only using script.sh stop vc1 or vc2 or uc1 or uc2
script.sh connect command should create two fifo and connect processes as shown in figure.
So you are asking for methods for IPC, with the sample code you provided, I think the best one is the use of pipes.
From the pipe() man page:
A pipe is a unidirectional data channel that can be used for interprocess communication
Basically, it is handled like a pair of file descriptors. First, you must init the pipe, and then create the childs using the fork() call, so both parents and childs share the resource. Then, using write and read methods, you can send data between them.
In this example I create a child which reads some data from the parent process:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
int pid;
char buffer[255];
int fd[2]; // channel 0 for reading and 1 for writing
pipe(fd);
pid = fork();
if(pid == 0) {
close(fd[1]); // close fd[1] since child will only read
read(fd[0], &buffer, sizeof(buffer));
close(fd[0]);
exit(0);
} else { // parent
close(fd[0]) // close fd[0] since parent will only write
// init buffer contents
write(fd[1], &buffer, sizeof(buffer));
close(fd[1]);
}
return 0;
}
As you can see pipe creates a pair of file descriptors, one for writing (number 1) and one for reading (number 0).
In my sample code, the child process closes the writing one, since it will only read, and the parent closes the reading one, since it will only write data.
Note that pipes are unidirectional, so if you want that both the childs and the parent write and read data from it, you should create two pipes (so 4 file descriptors) for each of the childs. An example of how to handle that situation:
int pipeA[2], pipeB[2];
pid = fork();
if (pid == 0) { // child will write to pipeB and read from pipeA
close(pipeA[1]); // closing pipeA writing fd
close(pipeB[0]); // closing pipeB reading fd
write(pipeB[1],&buffer, sizeof(buffer));
read(pipeA[0], &buffer2, sizeof(buffer2));
close(pipeA[0]);
close(pipeB[1]);
exit(1);
} else { // parent will write to pipeA and read from pipeB
close(pipeA[0]); // closing pipeA reading fd
close(pipeB[1]); // closing pipeB writing fd
read(pipeB[0], &buffer, sizeof(buffer));
write(pipeA[1], &buffer2, sizeof(buffer2));
close(pipeA[1]);
close(pipeB[0]);
}
If you want more info about pipes you can check the man page here.
Also, other simple ways of IPC would be the use of Unix Sockets, although I think that for the example you presented pipes will be enough.
You'r code create one parent and one child, not two child, so you need to add another fork into child block :
#include <stdio.h>
void main()
{
int pid,status;
pid = fork();
if(pid == -1) {
printf(“fork failed\n”);
exit(1);
}
if(pid == 0) { /* Child */
fork();// another child
if (execlp(“/bin/ls”, “ls”, NULL)< 0) {
printf(“exec failed\n”);
exit(1);
}
}
else { /* Parent */
wait(&status);
printf(“Well done kid!\n”);
exit(0);
}
}
I would like to create a small program that will accept user input from stdin for the number of processes they would like, and then, my program will fork the n number of processes as specified by the user. Later on, I would like to pipe data from the child to the parent.
However, I want only one parent process. I have been trying to figure out the algorithm for this, and perhaps I am overcomplicating it, but I am stuck.
Do note I can only use the fork and pipe features in C (so nothing too crazy!)
Here is my algorithm.
Loop only if I am a parent process, and do not loop if I am a child process.
If I am a parent process entering the loop, then I will call fork(). Otherwise, I am a child, and I will do some child-related tasks (which I may then pipe back to the parent later on). The child should not re-enter the loop as to avoid creating children-of-children processes.
Does that make any sense?
What would you advise me to do?
Let's say n is the number of children you get as input. Let's see what you could do, if you use one pipe for each child.
In the parent process:
pid_t pid;
int fd[n][2];
for(i = 0; i < n; i++) {
pipe(fd[i]);
pid = fork();
if (pid < 0) {
perror("whatever");
exit(1);
}
else if (pid == 0) {
for(j = 0; j < i; j++) {
if (close(fd[j][0]) < 0) {
perror("closing fd[0]");
exit(1);
}
if (close(fd[j][1]) < 0) {
perror("closing fd[1]");
exit(1);
}
}
func(fd[i]);
}
}
// other parent stuff next && close file discriptors not needed
And your func() should be what the children have to do. It takes as arguments the 2 file descriptors of the child's pipe. Note that in the end of func you should exit().
A solution making a pipe for each child would be a little better but a little more complex than that (hint: you may pass fd's as arguments, also close all fd's with caution!)
Also, you may keep each child's pid by defining pid_t pid[n]; instead of pid, and refer to each pid as pid[i].
Don't forget to wait for every child to die!
If it were me, I would move all of the fork() and pipe() stuff into its own subroutine, with clear semantics, and call that subroutine from a loop in main().
In the example below, spawn() forks, invokes the work function in child, ensures that the child exits appropriately, and returns in the parent.
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
/* Launch a child. This routine exit()s in the child and
* return()s in the parent */
void spawn(void (*fn)(int), int *fd) {
int pipefd[2];
int pid;
if(pipe(pipefd) < 0) {
perror("pipe");
exit(1);
}
switch(pid = fork()) {
case -1: /* Error */
perror("fork");
exit(1);
break;
case 0: /* Child */
close(pipefd[0]); /* Kids only talk */
fn(pipefd[1]); /* Put the kid to work */
exit(0); /* Kill the kid */
break;
default: /* Parent */
close(pipefd[1]); /* Parents only listen */
*fd = pipefd[0];
printf("Spawning PID=%d, FD=%d\n", pid, *fd);
break;
}
}
int
get_number_of_children() {
/* TODO: Do stdin-reading here and return a good number */
return 3;
}
void do_work(int fd) {
/* TODO: Whatever work the children might do */
/* For example: */
write(fd, "hello", 5);
}
int main (int ac, char **av) {
int nkids = get_number_of_children();
int fd_array[nkids];
int pid;
/* Birth the children */
for(int i = 0; i < nkids; i++) {
spawn(do_work, &fd_array[i]);
}
/* TODO: Read the data from the file descriptors in fd_array */
/* Finally, wait for all children to die */
while((pid = wait(0)) != -1) {
printf("Waited PID=%d\n", pid);
}
}
I'm a bit new to pipes and concurrency, and have been frustrated with this problem for hours. I am struggling to understand why this write operation is constantly failing on my pipe. I am trying to have the child process write data through a pipe that will be received by the parent process. My current code is this:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 4096
int main() {
pid_t status;
int fd[2]; //The array of file descriptors
if (pipe(fd) == -1) {
printf("Error piping");
}
status = fork(); //Begin the fork process
switch (status) {
case -1:
perror("Error forking");
break;
case 0:
//Child process
close(fd[0]); //Only send data
char some_string[15] = "hi there";
if (write(fd[1], some_string, MAXSIZE) == -1) {
printf("Error writing to the pipe");
}
close(fd[1]); //Close write end
exit(1);
default:
close(fd[1]); //Only receive data
char readed[500] = "";
while(read(fd[0], readed, MAXSIZE) != 0) {
printf("read this %s\n", readed);
}
printf("Done reading");
close(fd[0]);
break;
}
return 1;
}
However, I constantly get the message "Error writing to pipe", meaning that the write operation has failed in the child process. Another interesting thing is that if I change some_string to a string literal instead, this code works fine with the exception that it never terminates and instead, the read operation in the parent process reads from STDIN! I don't understand why this could be happening, is it possible that we have a zombie child when parent executes so the pipe is "dead"? Or perhaps that the parent process terminates and we have an orphaned child? How can I avoid this and how does this explain the weird behaviour from the string literal instead? Any insights?
You told write() to read the data from out-of-range of the array and allowed read() to write the data read to out-of-range of the array. That is very bad.
Write only valid data and limit the length to read not to cause out-of-range access.
Try this:
#include <unistd.h>
#include <sys/types.h> /* add this to use pid_t */
#include <sys/wait.h> /* add this to use wait() */
#include <stdio.h>
#include <stdlib.h>
/* remove unused MAXSIZE */
int main() {
pid_t status;
int fd[2]; //The array of file descriptors
int st; /* variable for receiving the status */
if (pipe(fd) == -1) {
printf("Error piping");
return 1; /* return 1 when the execution failed */
}
status = fork(); //Begin the fork process
switch (status) {
case -1:
perror("Error forking");
return 1; /* return 1 when the execution failed */
break;
case 0:
//Child process
close(fd[0]); //Only send data
char some_string[15] = "hi there";
if (write(fd[1], some_string, sizeof(some_string)) == -1) {
printf("Error writing to the pipe");
}
close(fd[1]); //Close write end
exit(0); /* return 0 if the execution finished successfully */
default:
close(fd[1]); //Only receive data
char readed[500] = "";
while(read(fd[0], readed, sizeof(readed) - 1) != 0) { /* -1 for reserving space for terminating null-character */
printf("read this %s\n", readed);
}
printf("Done reading");
close(fd[0]);
wait(&st); /* wait for the child process to exit and release the data of the process */
break;
}
return 0; /* return 0 if the execution finished successfully */
}
I am trying to write from one process to the another using two separate pipes. In the following manner:
child1 writes to parent (using pipe1)
parent writes to child2 (using pipe2)
I have no problems writing to the parent, but when I try to relay the data to child2, the file descriptor appears to be NULL and I'm not sure why. For clarity purposes, I tried to emboldened the areas that I am having problems with. I also removed a lot of the error handling.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
pid_t pid;
pid_t pid1;
int mypipe[2];
int mypipe1[2];
int file;
char buf[100];
FILE *stream;
FILE *stream2;
FILE *rm;
ssize_t numbersread;
if (pipe (mypipe))
{
fprintf (stderr, "Pipe failed.\n");
return EXIT_FAILURE;
}
if (pipe (mypipe1))
{
fprintf (stderr, "Pipe2 failed.\n");
return EXIT_FAILURE;
}
/* CREATE THE FIRST CHILD HERE. */
pid = fork ();
if (pid == (pid_t) 0)
{
rm = fopen("Readme.txt","r");
//10 BYTES AT A TIME
close(mypipe[0]);
for(k=0;k<=10;k++)
{
transmitor(mypipe[1],rm); // GO READ FILE AND THEN WRITE ON PIPE
}
fclose(rm);
return EXIT_SUCCESS;
}
// BACK TO THE PARENT PROCESS
else
{
/*OBJECTIVES:
1. READ THE FILE FROM THE PIPE
2. WRITE THE FILE ONTO A SECOND PIPE
3.SEND IT TO THE RECEIVER
*/
FILE *file1;
ssize_t numbersread1;
file1 = fdopen(mypipe[0],"r");
close (mypipe[1]);
close(mypipe1[0]);
stream2 = fdopen(mypipe1[1],"w");
while(!feof(file1)){
numbersread1 = fread(buf, 1, (sizeof buf),file1);
printf("%zd\n", numbersread1);
**fwrite(buf,1,numbersread1,stream2);**
buf[numbersread1] = 0;
}
printf("%s\n","finished parent");
fclose(file1);// FINISHED READING
fclose(stream2);
** /* CREATE THE SECOND CHILD HERE #2. */
/*OBJECTIVES:
1. READ DATA FROM PIPE
2. WRITE DATA TO FILE*/
pid1 = fork ();
sleep(2);
if (pid1 == (pid_t) 0)
{
/* This is the child process.
Close read end first. */
FILE *stream3;
stream3 = fdopen(mypipe1[0],"r");
close (mypipe1[1]);
if(stream3==NULL)
{
printf("%s","NULL Stream3 Variable");
}
else
{
while (!feof(stream3)) {
printf("\r\nIN WHILE\r\n");
numbersread = fread(buf, 1, (sizeof buf),stream3);
printf("%zd\n", numbersread);
buf[numbersread] = 0;
}
fclose(stream3);
}**
printf("%s","FINISHED RECEIVER");
return EXIT_SUCCESS;
}
return EXIT_SUCCESS;
}// THIS CLOSES THE FIRST ENTRANCE TO THE PARENT PROCESS WHERE WE ARE WRITING TO THE FIRST RECEIVER
}// THIS IS THE END OF THE MAIN FUNCTION
You close(2) file descriptors you use later, for example this bit of your code:
file1 = fdopen(mypipe[0],"r");
close (mypipe[1]);
close(mypipe1[0]);
you close mypipe1[0]. Further down you do:
FILE *stream3;
stream3 = fdopen(mypipe1[0],"r");
close (mypipe1[1]);
therefore stream3 will be NULL.
I would also strongly recommend to name the variables a bit more what they do. For example mypipe could be c1_to_parent and mypipe1 could be parent_to_c2. That would make your code a lot more readable.
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