I'm trying to send data between two pipes, that will go from parent->child->parent->child etc and so on until I exit the loop. Right now I'm trying to just pass an integer and increment it for each read done on it. At the moment it seems like each process is only incrementing it's own value and it's read component isn't working correctly. Are my pipes setup wrong?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER_SIZE 25
#define READ 0
#define WRITE 1
int main(void)
{
pid_t pid;
//open two pipes, one for each direction
int mypipefd[2];
int mypipefd2[2];
/* create the pipe */
if (pipe(mypipefd) == -1 || pipe(mypipefd2) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* now fork a child process */
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid > 0) { /* parent process */
int parentVal = 0;
while(1) {
close(mypipefd[READ]); //close read end, write and then close write end
parentVal++;
write(mypipefd[WRITE],&parentVal,sizeof(parentVal));
printf("Parent: writes value : %d\n", parentVal);
close(mypipefd[WRITE]);
close(mypipefd2[WRITE]); //close write end, read, and then close read end
read(mypipefd2[READ],&parentVal,sizeof(parentVal));
printf("Parent: reads value : %d\n", parentVal);
close(mypipefd2[READ]);
}
}
else { /* child process */
int childVal = 0;
while(1) {
close(mypipefd[WRITE]);
read(mypipefd[READ],&childVal,sizeof(childVal));
printf("child: read value : %d\n", childVal);
childVal++;
close(mypipefd[READ]);
close(mypipefd2[READ]); //close read end, write and then close write end
write(mypipefd2[WRITE],&childVal,sizeof(childVal));
printf("child: write value : %d\n",childVal);
close(mypipefd2[WRITE]);
}
}
}
In addition to what Jonathan Leffler said, I want to say that you should add checks to make sure that when read fails, you deal with the condition gracefully.
if (pid > 0) { /* parent process */
int parentVal = 0;
close(mypipefd[READ]); // The parent is not going to read from the first pipe.
// Close the read end of the pipe.
close(mypipefd2[WRITE]); // The parent is not going to write to the second pipe.
// Close the write end of the pipe.
while(1) {
parentVal++;
write(mypipefd[WRITE],&parentVal,sizeof(parentVal));
printf("Parent: writes value : %d\n", parentVal);
// If the chld closes the write end of the second pipe,
// break out of the loop.
if ( read(mypipefd2[READ],&parentVal,sizeof(parentVal)) > 0 )
{
printf("Parent: reads value : %d\n", parentVal);
}
else
{
break;
}
}
close(mypipefd[WRITE]); // Close the write end of the first pipe
close(mypipefd2[READ]); // Close the read end of the second pipe
}
else { /* child process */
int childVal = 0;
close(mypipefd[WRITE]); // The child is not going to write to the first pipe.
// Close the write end of the pipe.
close(mypipefd2[READ]); // The child is not going to read from the second pipe.
// Close the read end of the pipe.
while(1) {
// If the parent closes the write end of the first pipe,
// break out of the loop.
if ( read(mypipefd[READ],&childVal,sizeof(childVal)) > 0 )
{
printf("child: read value : %d\n", childVal);
}
else
{
break;
}
childVal++;
write(mypipefd2[WRITE],&childVal,sizeof(childVal));
printf("child: write value : %d\n",childVal);
}
close(mypipefd[READ]); // Close the read end of the first pipe
close(mypipefd2[WRITE]); // Close the write end of the second pipe
}
Your problem is that you're too enthusiastic about closing file descriptors. (That's a pleasant change from the usual; more often people don't close enough file descriptors.)
Each of the processes should close the ends of the pipes it is not going to use, but should do that before the loop. It should not close the pipes it is reading from or writing to if you want to iterate more than once. Those closes should be after the loop (and could be left out altogether since the program will terminate once the loop terminates, though it is generally better to explicitly close what you explicitly open). You should probably make sure that the loop does terminate (e.g. when the count reaches 1000).
Related
Let‘s assume we have a pipe int InPipe[2];. How can you read the input until the pipe is empty without blocking when the whole available Data input was read?
I know this question has been asked several times, but I couldn’t assemble a suitable function.
This is my Code so far:
int InPipe[2];
char buffer[1024];
int rc;
while (true){
read(InPipe[0], buffer, sizeof(buffer));
fprintf(stdout, “%s“, buffer);
bzero(&buffer, sizeof(buffer)); // Clearing Buffer
}
Any Ideas, Suggestions, Code Snippets
Reading from a pipe
Attempts to read from a pipe that is currently empty block until at
least one byte has been written to the pipe. If the write end
of a pipe is closed, then a process reading from the pipe will
see end-of-file (i.e., read() returns 0) once it has read all remaining
data in the pipe.
taken from linux interface programming.
You cant! the process reading from the pipe will be blocked in this situation.
Due to people comments, i am adding this section:
we can use a pipe to allow communication between two processes. To con-nect two processes using a pipe, we follow the pipe() call with a call to fork(). immediately after the fork(), one process closes its descriptor for the write end of the pipe, and the other closes its descriptor for the read end. For example, if the parent is to send data to the child, then it would close its read descriptor for the pipe, filedes[0], while the child would close its write descriptor for the pipe, filedes[1], then the code for this will be:
int filedes[2];
if (pipe(filedes) == -1) /* Create the pipe */
errExit("pipe");
switch (fork()) /* Create a child process */
{
case -1:
errExit("fork");
case 0: /* Child */
if (close(filedes[1]) == -1) /* Close unused write end */
errExit("close");
/* Child now reads from pipe */
break;
default: /* Parent */
if (close(filedes[0]) == -1) /* Close unused read end */
errExit("close");
/* Parent now writes to pipe */
break;
}
There are a couple of key things mentioned in the comments, i.e. non-blocking IO, and performing the read in its own thread, along with some other suggestions. The example here goes into detail explaining its architecture. Only the code section is reproduced below as I believe it to be a decent illustration of several of these comments. The example code is commented throughout. Read them, they serve as a good tutorial:
// C program to demonstrate use of fork() and pipe()
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
int main()
{
// We use two pipes
// First pipe to send input string from parent
// Second pipe to send concatenated string from child
int fd1[2]; // Used to store two ends of first pipe
int fd2[2]; // Used to store two ends of second pipe
char fixed_str[] = "forgeeks.org";
char input_str[100];
pid_t p;
if (pipe(fd1)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
if (pipe(fd2)==-1)
{
fprintf(stderr, "Pipe Failed" );
return 1;
}
scanf("%s", input_str);
p = fork(); //Note - the return of fork can be less than, greater
// than or equal to zero. Each is significant in
// knowing how to direct program flow, as shown
// in this section...
if (p < 0)
{
fprintf(stderr, "fork Failed" );
return 1;
}
// Parent process
else if (p > 0)
{
char concat_str[100];
close(fd1[0]); // Close reading end of first pipe
// Write input string and close writing end of first
// pipe.
write(fd1[1], input_str, strlen(input_str)+1);
close(fd1[1]);
// Wait for child to send a string
wait(NULL);
close(fd2[1]); // Close writing end of second pipe
// Read string from child, print it and close
// reading end.
read(fd2[0], concat_str, 100);
printf("Concatenated string %s\n", concat_str);
close(fd2[0]);
}
// child process
else
{
close(fd1[1]); // Close writing end of first pipe
// Read a string using first pipe
char concat_str[100];
read(fd1[0], concat_str, 100);
// Concatenate a fixed string with it
int k = strlen(concat_str);
int i;
for (i=0; i<strlen(fixed_str); i++)
concat_str[k++] = fixed_str[i];
concat_str[k] = '\0'; // string ends with '\0'
// Close both reading ends
close(fd1[0]);
close(fd2[0]);
// Write concatenated string and close writing end
write(fd2[1], concat_str, strlen(concat_str)+1);
close(fd2[1]);
exit(0);
}
}
Can you please explain me why is the child process able to read even after the parent closes its write end?
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
int fd[2];
char buffer[20];
pipe(fd);
if ( fork() == 0 ) //child
{
close(fd[0]); //As it is writing close the read end
strcpy(buffer, "Hello World");
write(fd[1], buffer, sizeof(buffer));
close(fd[1]);
}
else //parent
{
close(fd[1]); //As it is reading closing the write end
while(1)
{
read(fd[0], buffer, sizeof(buffer));
printf("Buffer:%s\n", buffer);
sleep(1);
}
close(fd[0]);
}
}
O/P: Child continuously prints:
Buffer:Hello World
Why is the child able to receive even when the parent terminates? Shouldn't read get EOF?
Why is the child able to receive even when the parent terminates? Shouldn't read get EOF?
At that point the parent process is basically reading nothing (i.e.: read() is returning 0) and printing over and over what it had read in a previous call to read().
You have to look at the value returned by the read() system call. That value is of type int, and basically :
-1: error, something went wrong.
0: nothing else remaining to read, i.e.: EOF (what you were looking for).
Otherwise: the number of bytes read by read() that were stored into buffer.
You can rewrite the parent's while-loop accordingly:
while(1) {
int count = read(fd[0], buffer, sizeof(buffer));
switch (count) {
case 0: // EOF
break;
case -1: // read() error
// ... error handling ...
break;
default: // fine
// count contains the number of bytes read
buffer[count] = '\0'; // NUL character, to indicate the end of string
printf("Buffer:%s\n", buffer);
sleep(1);
}
}
So,my programm should do this: I write in the parent process a message to the file "vaterkind" and then read it with the child process, write it to a string and put it on the screen. I tried with this code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
int main()
{
FILE *vaterkind, *kindvater;
char path1[]={"/home/user/Documents/vaterkind"}, path2[]={"/home/user/Documents/kindvater"}; //paths to files
int ret, readyv=0, readyk=0;
mkfifo(path1,0666); //makes fifos
mkfifo(path2,0666);
ret = fork();
if(ret > 0) //parent
{
char data_in[50];
char data_out[50];
puts("String");
gets(data_in);
vaterkind = open(path1,O_WRONLY); //dad is able to write
kindvater = open(path2,O_RDONLY); //child is able to read
write(vaterkind,data_in,strlen(data_in)); //write input in vaterkind
puts("String sent");
readyv = 1; // set ready
}
else if(ret == 0) // child
{
char data[50],hex[50],ascii[50];
int i = 0, j = 0;
vaterkind = open(path1,O_RDONLY); //dad is able to read
kindvater = open(path2,O_WRONLY); //child is able to write
read(vaterkind,data,strlen(data)); //read input and write to data
puts(data);
puts("Child finished");
return 0;
}
else
{
puts("Fork failed");
}
sleep(1);
return 0;
}
But when I start the program I first get the message "String" then a symbol (don't know why a symbol is here) then "Child finished" then I can do the gets from the parent and then "String sent" it looks like this:
String
Child finished
input
String sent
Can somebody help out please?
In the child branch
char data[50];
...
read(vaterkind,data,strlen(data))
At that point data contains garbage and applying strlen to it makes no sense at all.
(That's not even mentioning that the parent sends a string without a zero-terminator and the child never bothers to zero-terminate what it received.)
You are supposed to develop a communication protocol of some sort to make sure that at any point the child knows how many bytes it should read from FIFO. For example, the parent can first send the length of the string and only then the contents of the string. The child begins by reading the length and proceeds from there.
Your read in child process is not blocked.
so it wont wait till parent process is finished.
you have to use a pipe from parent to child.
Write into pipe from parent end.
read from the pipe in child.
This blocks the child process, till reading is complete.
Below is simple design for your understanding and how to do it.
int main(int argc, char *argv[])
{
//Two file descriptors for pipe read and write.
int fd[2];
// create a pipe with defined file descriptors
pipe(fd);
// fork() returns 0 for child process.
//so below is a parent process.
if (fork() != 0)
{
// close read-descriptor, you are only writing in parent.
close(fd[0]);
//write into the pipe
write(fd[1], "your data to write", sizeof("your data"));
// close the write descriptor
close(fd[1]);
}
else
{
// close the write-descriptor, you are only reading here
close(fd[1]);
// read here. this will block the process till your reading complete.
read(fd[0], "your variable to read", sizeof("your variable"));
// close the read-descriptor
close(fd[0]);
}
return 0;
}
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.
A Process creates a child process, increase x by 1, then send x value to the child process, the child process can then multiply x by 10, and pass x back to the parent process and so on. You should at least do this 5 times.
the output should look like this:
initial value 0
Parent:
x value after operation:1
Child:
x value after operation:10
Parent:
x value after operation:11
Child:
x value after operation:110
Parent:
x value after operation:111
Child
x value after operation:1110
What i have is the following.......
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
#define READ 0
#define WRITE 1
int main()
{
pid_t pid;
int mypipefd[2];
int ret;
int i;
int x=0;
int result,result2;
ret = pipe(mypipefd);
if(ret ==-1) //test for pipe
{
perror("pipe"); //show error and exit
exit(1);
}
printf("initial value %d\n", x);
pid = fork();
for(i=0;i<5;i++)
{
if(pid == 0)
{
/*Child process*/
result2=result*10;
write(mypipefd[WRITE],&result2,sizeof(result2));
printf("Child:\nx value after operation: %d\n", x);
close(mypipefd[WRITE]);
read(mypipefd[READ],&result2,sizeof(result2));
printf("=======================================\n");
close(mypipefd[READ]);
}
else if(pid > 0)
{
/*Parent process*/
result=x++;
write(mypipefd[READ],&result,sizeof(result));
printf("Parent:\nx value after operation: %d\n", x);
close(mypipefd[WRITE]);
read(mypipefd[WRITE],&result,sizeof(result));
printf("=======================================\n");
close(mypipefd[READ]);
exit(0);
}
else
{
perror("fork");
exit(1);
}
}
}
The question is, what's wrong with my code? I tried to READ and WRITE back the the pipe but seems not working...
What's the output of my code right now:
initial value 0
Parent:
x value after operation:1
Child:
x value after operation:0
Child:
x value after operation:0
Child:
x value after operation:0
Child:
x value after operation:0
Child:
x value after operation:0
I think the first issue to address is that you have both ends of the pipe open when you are trying to read/write data. If you are writing data to the pipe you would
close(fd[READ_END])
write(...)
close(fd[WRITE_END])
Second, pipes in unix are simplex. You seem to be trying to read and write from the pipe at the same time. If you want to do this you are going to have to open two pipes.
I modified your program to show you how to read from pipe and then write to pipe for parent/child. Hopefully this helps you.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#define BUFFER_SIZE 25
#define READ 0
#define WRITE 1
int main(void)
{
pid_t pid;
//open two pipes, one for each direction
int mypipefd[2];
int mypipefd2[2];
/* create the pipe */
if (pipe(mypipefd) == -1 || pipe(mypipefd2) == -1) {
fprintf(stderr,"Pipe failed");
return 1;
}
/* now fork a child process */
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork failed");
return 1;
}
if (pid > 0) { /* parent process */
int writeValue=10;
int readValue=0;
close(mypipefd[READ]); //close read end, write and then close write end
write(mypipefd[WRITE],&writeValue,sizeof(writeValue)); //write to pipe one
printf("Parent: writes value : %d\n", writeValue);
close(mypipefd[WRITE]);
close(mypipefd2[WRITE]); //close write end, read, and then close read end
read(mypipefd2[READ],&readValue,sizeof(readValue));
printf("Parent: reads value : %d\n", readValue);
close(mypipefd2[READ]);
}
else { /* child process */
int writeValue=20;
int readValue=0;
close(mypipefd[WRITE]); //close write end, read, and then close read end
read(mypipefd[READ],&readValue,sizeof(readValue));
printf("child: read value : %d\n", readValue);
writeValue+=readValue;
close(mypipefd[READ]);
close(mypipefd2[READ]); //close read end, write and then close write end
write(mypipefd2[WRITE],&writeValue,sizeof(writeValue));
printf("child: writeValue value : %d\n", writeValue);
close(mypipefd2[WRITE]);
}
return 0;
}
This open two pipes. The parent writes a value to the first pipe and the child reads this value. The child updates this values, and writes it to the second direction pipe. The parent then reads this value and vuela! two way pipe communication.
Output:
Parent: writes value : 10
child: read value : 10
child: write value : 30
Parent: reads value : 30
This can be extended to your application as such
if (pid > 0) { /* parent process */
result1++;
close(mypipefd[READ]); //close read end, write and then close write end
write(mypipefd[WRITE],&result1,sizeof(result1)); //write to pipe one
printf("Parent:\n x value after operation: %d\n", result1);
close(mypipefd[WRITE]);
close(mypipefd2[WRITE]); //close write end, read, and then close read end
read(mypipefd2[READ],&result1,sizeof(result1));
close(mypipefd2[READ]);
}
else { /* child process */
close(mypipefd[WRITE]); //close write end, read, and then close read end
read(mypipefd[READ],&result2,sizeof(result2));
result2*=10;
printf("child:\n x value after operation %d\n", result2);
close(mypipefd[READ]);
close(mypipefd2[READ]); //close read end, write and then close write end
write(mypipefd2[WRITE],&result2,sizeof(result2));
close(mypipefd2[WRITE]);
}
If you put this in the loop then it would theoretically work. HOWEVER, The order of execution will be jumbled between the two processes due to context switching and other OS related scheduling. This means that reads and writes are not necessarily sequential the way you are doing it, And it wont work. Read into this question
How to wait till data is written on the other end of pipe.