I have this code:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#define READ 0
#define WRITE 1
char* phrase = "Hello";
void PIPE(){
int fd [2], bytesRead;
char message [100]; /* Parent process' message buffer */
pipe (fd); /*Create an unnamed pipe */
if (fork () == 0) /* Child, writer */
{
close(fd[READ]); /* Close unused end */
write (fd[WRITE],phrase, strlen (phrase) + 1);
close (fd[WRITE]); /* Close used end*/
}
else /* Parent, reader*/
{
close (fd[WRITE]); /* Close unused end */
bytesRead = read (fd[READ], message, 100);
printf ("Read %d bytes: %s\n", bytesRead, message); /* Send */
close (fd[READ]); /* Close used end */
}
}
I'm studying the Pipe in C , and my book says:
If a process reads from a pipe whose write end has been closed, the read () returns a 0, indicating end-of-input.
but in the code(in the parent part) , before read function the write part has close and the read function doesn't return 0 but 5(lenght of Hello).
what is wrong?
thank for your time
UPDATE 1:
I have another question for you(I understand the first problem ):
at the beginning if the reader reads empty pipe, the read function returns 0, but how can I be sure this is the first writer to start and then after the reader ?
It should include "once all written data has been read". Otherwise a pipe would not make much sense. Or would require to explicitly signal to the writer the reader has taken all data from the pipe before closing - breaking its file semantics.
First of all, you dont know whether the pipe was closed when the parent reads from it. Since there are two proccesses involved, the scheduler decides which process runs next and for how long - not the order of your code.
Secondly, as already said, the string written to the pipe is still in it's buffer. Thus, the parent will read everything that's in the buffer before it returns EOF.
This is true for empty pipe as POSIX says:
When attempting to read from an empty pipe or FIFO:
If no process has the pipe open for writing, read() shall return 0 to indicate end-of-file
Answer update 1:
Pipes (in normal blocking mode) provide synchronization at both ends : reader is blocked while pipe is empty, and writer is blocked while pipe is full.
You have no need to ensure writer writes before reader reads or something like that. If the reader tries to read an empty pipe it will be blocked until : either someone else writes in the pipe or the last writer closes its end.
Related
My program creates child process and sets pipes to communicate with it. The problem occurs when i try to read data from the pipe. Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe). But instead read just freezes and waits for more data to come.
What am i missing here?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void setfd(int *in, int *out) {
dup2(out[1], 1);
dup2(in[0], 0);
}
int main(int argc, char *argv[]) {
int status;
int pipe2ch[2], pipe2pr[2];
char *newargv[] = {NULL, NULL};
newargv[0] = argv[1];
pipe(pipe2ch);
pipe(pipe2pr);
setfd(pipe2pr, pipe2ch);
int a;
if (!(a = fork())) {
setfd(pipe2ch, pipe2pr);
execve(newargv[0], newargv, NULL);
exit(1);
} else {
printf("hello!\n");
fflush(stdout);
char str;
wait(&status);
while (read(pipe2pr[0], &str, 1) > 0) {
fprintf(stderr, "%c", str);
}
exit(0);
}
}
Since child process has ended (i use wait to ensure that) EOF should be on the end of the data stream thus ending the read (As in the man page for pipe).
I'm not sure what you've read to suggest that. Or maybe it's your wording that I don't understand. EOF is not a character on the stream.
But instead read just freezes and waits for more data to come. What am i missing here?
Several things. The most important one is probably that when a process forks, the child's copies of the parent's open file descriptors refer to the same entries in the kernel's underlying table of open files as the parent's do, each of which remains open until all handles on it are closed. The child closes all its file descriptors when it exits, but both ends of both pipes remain open in the parent, so end-of-file will not be signaled to readers. Each process must close the pipe ends it doesn't use or is finished using.
Additionally, you should read() first, then wait(), for if the child process writes enough data to the pipe then it may block, and if the parent does not read until after the child exits then you'll have a deadlock.
Furthermore, I don't see any reason to dupe either pipe end onto the parent's standard streams (resulting in closing the original ones). Just manipulate the pipes via their file descriptors, as you already half do. If you want a stream interface to those, then use fdopen() to get one.
In the below program (which is not mine, but one which I have modified), the child process makes two writes to the pipe. When I run the program, I get the following output:
Received string: Hello, world!
This is the child process.
How is it that the read performed by the parent process captures both of these strings from the pipe buffer? What (if anything) prevents the parent process from assuming after it has read the first string (or the first char of the first string for that matter) that there is nothing else to read from the buffer, and exiting?
Program in question:
int main(void)
{
int fd[2], nbytes;
pid_t childpid;
char string[] = "Hello, world!\n";
char string2[] = "This is the child process.\n";
char readbuffer[80];
pipe(fd);
if((childpid = fork()) == -1)
{
perror("fork");
return 1;
}
if(childpid == 0)
{
/* Child process closes pipe's input file descriptor */
close(fd[0]);
/* Send "string" through the output side of pipe */
write(fd[1], string, (strlen(string)));
write(fd[1], string2, (strlen(string2)+1));
return 1;
}
else
{
/* Parent process closes pipe's output file descriptor */
close(fd[1]);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
return 0;
}
The key here is the read() buffer size 80.
Usually read() block the process which is calling it (is set in a sleeping status) until certain conditions doesn't happen, for example:
the requested buffer is full
there's less data than requested (EOF) or an error occurred
a signal wake the process (as ^C), this may be your case, the child process exit and the system send a broken pipe signal to the parent (the process wake and read() get the whole buffer)
Note that those conditions depends on the subsystem you are reading from, in your case a pipe. Subsystem which may have different properties, like buffer size. An absurd example: if pipe buffer size on kernel side was less than or equal to your first write, the reading process would have wake up earlier returning a truncated buffer.
I love this question. It makes me remember old time ...
Meta-answer: It does only know, if the stream is closed
Answer: your process reads all it can/has to read, no end stops at '\n'
But I suppose, you want to write/read records.
Despite others I try to answer without distinguishing types of streams. I make a disclaimer here:
it all depends on OS and stream type - and the options opening on both (!) sides
Basic:
Lets say one process writes an other reads - easy enough.
No is not.
Imagine - always ;-) - they put there chars (bytes) into the stream as they want and can - slowly - fast - one by one or all they buffered.
and you read it - no - not you and not your program - in between - byte by byte or on block or how the layer in between likes.
So if you want a record, there a only three possibilities:
make an end char(byte) - block seperator,
make the records fix length,
the old two-byte-length then read the rest
Answer again:
in your case the child puts all chars in the stream the parent read them and over - why should one of them make a break?
Solution:
Depending on the OS and language and libs, you sometimes can tell the OS to make an / accept an end char (like \n) - sometimes your write read functions do that for you
The parent will read a maximum of 80 bytes. So the first write system call (and also the second) will place the first string in the kernel buffer relative to the pipe. The read system call will read a maximum of 80 bytes, so it will ask to the kernel for the data, and the kernel will return the first 80 bytes of data in the buffer (so it is impossible to read only the first character of the string with a single write of the entire string and a single blocking read of 80 bytes).
As you stated there is no synchronization between the child and the parent.
In fact on my linux system your program sometimes print only the first string, sometimes its print both.
The problem is a classic Race Condition problem, sometimes the child will write only the first string, then the parent is scheduled and it will read the first string, then the program will end (or the control will return to the child after the read, the child will write the second string to the pipe buffer but no one will actually read the data).
You should place some synchronization functions in your program, an example can be to place a wait for the child after the close(fd[1]);
[...]
else
{
/* Parent process closes up output side of pipe */
close(fd[1]);
/* Synchronize parent and child */
wait(NULL);
/* Read in a string from the pipe */
nbytes = read(fd[0], readbuffer, sizeof(readbuffer));
printf("Received string: %s", readbuffer);
}
[...]
Then the parent will read the data only when the two strings are correctly placed in the buffer.
this is an example of how to write to a pipe.
This example is for parent writing to child, but the logic is very similar, regardless of the data flow direction.
close(pipefd[0]); /* Close unused read end */
write(pipefd[1], argv[1], strlen(argv[1]));
close(pipefd[1]); /* Reader will see EOF */
wait(NULL); /* Wait for child to exit */
exit(EXIT_SUCCESS);
Amongst other things, this means the caller to read() will get a returned value of 0 when everything is read from the pipe.
this also means the reader to read in a loop until a error condition indication is returned or a 0 is returned.
... how does the read function “know” when there is nothing left to read?
On success read() returns a much as available in the underlying object but not more then requested.
From man 3 read (POSIX):
Upon successful completion, where nbyte is greater than 0, read() shall mark for update the st_atime field of the file, and shall return the number of bytes read. This number shall never be greater
than nbyte. The value returned may be less than nbyte if the number of bytes left in the file is less than nbyte, if the read() request was interrupted by a signal, or if the file is a pipe or FIFO
or special file and has fewer than nbyte bytes immediately available for reading.
I wrote the following code in order to use pipes in c unix:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int main ()
{
int fds[2];
pid_t pid;
/* Create a pipe. File descriptors for the two ends of the pipe are
placed in fds. */
pipe (fds);
/* Fork a child process. */
pid = fork ();
if (pid == (pid_t) 0) {
//char abc[10]; - **Uncommenting this cause the program not to work.**
/* This is the child process. Close our copy of the write end of
the file descriptor. */
close (fds[1]);
// Read params
FILE * stream;
stream = fdopen (fds[0], "r");
char* args[4]={"avg3.out","4","3","5"};
/* Replace the child process with the “avg3” program. */
execv("avg3.out", args);
} else {
/* This is the parent process. */
FILE* stream;
/* Close our copy of the read end of the file descriptor. */
close (fds[0]);
/* Convert the write file descriptor to a FILE object, and write
to it. */
dup2(fds[0], STDOUT_FILENO);
stream = fdopen (fds[1], "w");
fprintf (stream, "5 4 3");
fflush (stream);
close (fds[1]);
/* Wait for the child process to finish. */
waitpid (pid, NULL, 0);
}
return 0;
}
avg3.out is a file I compiled before. It simply calculate the average of the 3 params sent to it.
The output was 4, but when I tried to actually read from the stream, I added a declaration for char buffer[10] The code stopped working. That is, no output provided. I tried to rename it, to move the decleration to the start of the if statement. but nothing worked.
So, why does the program stop working when adding just an array declaration?
The parameter-array to go with calls to exec*() needs to be (char*)NULL-terminated.
This line
char* args[4]={"avg3.out","4","3","5"};
should be
char* args[] = {"avg3.out", "4", "3", "5", NULL};
As it isn't in your code, exec() might get lost searching for it.
By bad luck the stack might have been clean (0 filled) for the version of your code not declaring a and execv() found a NULL right after the pointer pointing to "5". Having a created on the stack then changed the content of the stack which made execv() getting lost searching for the NULL.
Additionally its worth mentioning that the OP's code misses error checking on most of the relevant system call.
Having done so together with a detailed examation of the errors' causes, probably by using calls to perror() might have led to solving this issue by providing relevant information.
In particular placing it after the call to execv() it soon would have been obvious what's wrong:
execv("avg3.out", args);
perror("execv() failed");
I want to learn how Linux pipes work! I wrote a small and easy program that use a pipe to communicate a string between parent and child process. However, the program results in a dead lock that I have not understood what is its cause.
Here is the code :
#include <sys/wait.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define SIZE 100
int
main(int argc, char *argv[])
{
int pfd[2];
int read_pipe=0, write_pipe=0;
pid_t cpid;
char buf[SIZE];
/* PIPE ***************************************
* pipe() creates a pair of file descriptors, *
* pointing to a pipe inode, and places them *
* in the array pointed to by filedes. *
* filedes[0] is for reading, *
* filedes[1] is for writing *
**********************************************/
if (pipe(pfd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
read_pipe=pfd[0];
write_pipe=pfd[1];
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Child reads from pipe */
char * hello = "I am a child process\n";
sleep(1);
// wait until there is some data in the pipe
while (read(read_pipe, buf, SIZE) > 0);
printf("Parent process has written : %s\n", buf);
write(write_pipe, hello, strlen(hello));
close(write_pipe);
close(read_pipe);
_exit(EXIT_SUCCESS);
} else { /* Parent writes argv[1] to pipe */
char * hello = "I am a parent process\n";
write(write_pipe, hello, strlen(hello));
while (read(read_pipe, buf, SIZE) > 0);
printf("Child process has written : %s\n", buf);
close(write_pipe);
close(read_pipe);
wait(NULL); /* Wait for child */
exit(EXIT_SUCCESS);
}
}
In this link you'll find the proper mannipulation of PIPEs between parent and child. Your problem here is that the communication is not being correctly set-up.
The PIPE should be used to communicate in only one direction, so one process has to close the read descriptor and the other has to close the write descriptor. Otherwise what will happen is that the call to 'read'(both on the father and the son), since it can detect that there is another process with an open write descriptor on the PIPE, will block when it finds that the PIPE is empty (not return 0), until someone writes something in it. So, both your father and your son are getting blocked on their respective read.
There are two solutions to this:
.You create two PIPEs, one for the communication in each direction, and perform the initialization as explained in the link above. Here you have to remember to close the write descriptor when you are done sending the message, so the other process' read will return, or condition the loop to the count of bytes read (not to the return of read), so you won't perform another call when you read the whole message. For example:
int bread = 0;
while(bread < desired_count)
{
bread += read(read_pipe, buf + bread, SIZE - bread);
}
.You create one PIPE as you did, and modify the flags on the read descriptor, using fcntl to also have O_NONBLOCK, so the calls to read won't block when there's no information in the PIPE. Here you need to check on the return value of the read to know you received something, and go adding up until you get the full length of the message. Also you will have find a way to synchronize the two processes so they won't read messages that are not meant for them. I don't recommend you to use this option, but you can try it if you want using condition variables.
Maybe you can tell if you see any of yout printf() outputs?
Anyway, if you want to establish a two way communication between your paent and child, yout should use two pipes, one for writing data form parent to child an the other for writing from child to parent. Furthermore, your read loops may be dangerous: if the data comes in two or more chunks the second read() overwrites the first portion (I've never seen tha happen with local pipes, but for example with sockets). And of course, yout is not automatically null terminated after read(), so just printing int with "%s" may also cause problems.
I hope that gives you some ideas to try.
This question already has answers here:
Execute program from within a C program
(6 answers)
Closed 8 years ago.
How do I run another program from within my C program, I need to be able to write data into STDIN(while execution of program i have to provide input through stdin more than once) of the programed launched (and read line by line from it's STDOUT)
I need the solution to work under Linux.
while going through net i found below code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
void error(char *s);
char *data = "Some input data\n";
main()
{
int in[2], out[2], n, pid;
char buf[255];
/* In a pipe, xx[0] is for reading, xx[1] is for writing */
if (pipe(in) < 0) error("pipe in");
if (pipe(out) < 0) error("pipe out");
if ((pid=fork()) == 0) {
/* This is the child process */
/* Close stdin, stdout, stderr */
close(0);
close(1);
close(2);
/* make our pipes, our new stdin,stdout and stderr */
dup2(in[0],0);
dup2(out[1],1);
dup2(out[1],2);
/* Close the other ends of the pipes that the parent will use, because if
* we leave these open in the child, the child/parent will not get an EOF
* when the parent/child closes their end of the pipe.
*/
close(in[1]);
close(out[0]);
/* Over-write the child process with the hexdump binary */
execl("/usr/bin/hexdump", "hexdump", "-C", (char *)NULL);
error("Could not exec hexdump");
}
printf("Spawned 'hexdump -C' as a child process at pid %d\n", pid);
/* This is the parent process */
/* Close the pipe ends that the child uses to read from / write to so
* the when we close the others, an EOF will be transmitted properly.
*/
close(in[0]);
close(out[1]);
printf("<- %s", data);
/* Write some data to the childs input */
write(in[1], data, strlen(data));
/* Because of the small amount of data, the child may block unless we
* close it's input stream. This sends an EOF to the child on it's
* stdin.
*/
close(in[1]);
/* Read back any output */
n = read(out[0], buf, 250);
buf[n] = 0;
printf("-> %s",buf);
exit(0);
}
void error(char *s)
{
perror(s);
exit(1);
}
but this code is working fine if my C program(which needs to be executed usng exec) is reading input only once from stdin and returns output
once .but if my Cprogram(which needs to be executed usng exec) is taking input more than once(dont know exactly how many times it will read input from stdin)
and display output put mork than once(while execution display output line by line on stdout)
then this code is crashing. can any body suggest how to solve this problem?
Actually my C program(which needs to be executed usng exec) is displaying some output line by line and depending upon output i have to provide input on stdin
and number of this read/write is not constant.
Please help me resolve this issue.
You can use the select api to get notified when you can read/write a file descriptor.
So you would basically put your read and write calls into a loop, and run select to find out when the external program consumed some bytes or wrote something to stdout.