I have an assignment in which I need to declare a pipe in a header file. I really have no idea how to do this. It might be a really stupid question and I might be missing something obvious. If you could point me in the right direction I would greatly appreciate it.
Thanks for your time.
EDIT:
Sorry about the question being so vague. Maybe I need to reinforce my understanding of pipes.
I'm trying to create a pipe between two child processes. One child will write random characters into the pipe while the other child will read characters out of the pipe.
I guess I don't really understand what happens when I write something like:
int fd[2];
pipe = pipe(fd);
Am I right in saying that the writing and reading file descriptors for the pipe are put into fd[0] and fd[1] respectively? If in one of the child processes I close fd[1], that child could be thought of as my writer, correct?
EDIT 2:
Okay, it looks as if I pretty much have everything figured out and done, except I am getting an error pertaining to the file descriptors.
My code looks like this: (This is only the code relating to the pipe)
proj2.h
extern int fd[2];
proj2.c
int fd[2];
pipe(fd);
writer.c
close(fd[0]);
result = write(fd[1], &writeBuffer, sizeof(writeBuffer));
if(result < 0){
perror("Write");
}
reader.c
close(fd[1]);
result = read(fd[0], &readBuffer, sizeof(readBuffer))
if(result < 0){
perror("Read");
}
After executing the code, I get an error for every iteration of read() and write() with the error "Bad file descriptor". I've tried searching online to solve this myself, but I do not think I know enough about this material in order to do so. Any direction would be greatly appreciated once again. Everybody that has contributed has done a wonderful job so far, thank you very much. Also, if it looks like I'm just having you do my homework for me, I'm putting forth an honest effort and this isn't the entirety of the assignment.
EDIT 3:
Is the write() system call writing to standard output? What if I only want the contents to be printed after the reader reads them out of the pipe? How do I write them into the pipe without it writing them to standard output?
EDIT 4:
I've figured everything out now. Thanks for all of the help everybody. The only thing I'm still curious about is if I could somehow get the status of the parent process. I've collected the statuses from the child process using the wait() system call and was wondering how to retrieve the status of the parent process.
Here's an example of a program that creates a pipe and then forks the process and calls a sender function in the parent and a receiver in the child. The pipe creation and file descriptors are in one source code file with an associated header file, as are the sender and receiver. The main file requests the pipe be created then does the fork() and calls the sender and receiver functions.
pipe.h - this contains the extern declaration for the pipe file descriptors as well as the declaration of the function that creates the pipe:-
#ifndef PIPE_H
#define PIPE_H
extern int pipe_fd[2];
void create_pipe(void);
#endif
pipe.c - contains the actual definition of the pipe_fd array:-
#include "pipe.h"
#include <unistd.c>
int pipe_fd[2];
void create_pipe(void)
{
pipe(pipe_fd);
}
sender.h - declares the prototype for the sender() function
#ifndef SENDER_H
#define SENDER_H
void sender(void);
#endif
sender.c:-
#include "sender.h"
#include "pipe.h"
#include <unistd.h>
#include <stdio.h>
void sender(void)
{
char buf[]="Hello world";
printf("Sender: PID = %d\n", getpid());
close(pipe_fd[0]);
write(pipe_fd[1], buf, sizeof(buf));
}
receiver.h:-
#ifndef RECEIVER_H
#define RECEIVER_H
void receiver(void);
#endif
receiver.c - mirror image of sender
#include <stdio.h>
#include <unistd.h>
#include "receiver.h"
#include "pipe.h"
void receiver(void)
{
int bytes;
char buf[101];
printf("Receiver: PID = %d\n", getpid());
close(pipe_fd[1]);
bytes = read(pipe_fd[0], buf, 100);
buf[bytes]='\0';
printf("Receiver got: %s\n", buf);
}
main.c - ties it all together
#include "pipe.h"
#include "sender.h"
#include "receiver.h"
#include <sys/types.h>
#include <unistd.h>
void launch_sender_receiver(void)
{
pid_t forkpid;
forkpid = fork();
if (forkpid == 0)
receiver(); /* child */
else
sender();
}
int main(int argc, char* argv[])
{
create_pipe();
launch_sender_receiver();
return 0;
}
Hopefully you can follow all this from the code but if not here's a little extra explanation.
The create_pipe() function in pipe.c creates a pipe and puts the two file descriptors into file_fd. The pipe.h file provides an extern declaration for the file descriptors so that they can be accessed by the sender and receiver files (better programming practice would be to provide "getter" functions for these file descriptors in pipe.h so that sender() and receiver() are not accessing global variables).
Sender and Receiver use the pipe_fd array to either write or read from the pipe after they close the file descriptor that they don't need. The main() function ties it all together by calling the pipe creation function and then doing the fork and calling sender or receiver depending on whether it is the parent or child respectively.
Running this as a complete program should get you the following output (although of course the PIDs you get will be different):-
Receiver: PID = 3285
Sender: PID = 3284
Receiver got: Hello world
Does all that make sense?
Your question is almost impossibly vague, but I'm going to guess
extern int myPipe[2];
?
If you intend to fork() to create the two processes then your "int fd[2]; pipe(fd);" will work as you described.
i.e. use fd[0] in one process and fd[1] in the other.
However, if you're not going to fork then you're probably going to have to create a pipe in the filesystem and communicate through this.
Use mkfifo to create your pipe and then open it for reading in one process and open it for writing in the other.
Why do you need to do it in a header file?
You just call pipe() from your program.
Then call fork().
As a result you have two processes accessing the same pipe.
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…)
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.
Suppose I use pipefdn[2] and pipe() on it , can bidirectional communication be implemented using a single pipe or do you need 2 pipes ?
Though this operation results as success in some cases, but it is not a recommended way , especially in the production code. As pipe() by default dont provide any sync mechanism and moreover the read() can go for an infinite hang, if no data or read() is called before write() from other process.
Recommended way is to always use 2 pipe. pipe1[2], pipe2[2] for two way communication.
For more info please refer the following video description.
https://www.youtube.com/watch?v=8Q9CPWuRC6o&list=PLfqABt5AS4FkW5mOn2Tn9ZZLLDwA3kZUY&index=11
No sorry. Linux pipe() is unidirectional. See the man page, and also pipe(7) & fifo(7). Consider also AF_UNIX sockets, see unix(7).
Correct me if I am wrong: But I think you can. The problem is that you probably don't want to do that. First, of all create a simple program:
#include <stdio.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int pd[2];
int num = 2;
int main(){
pid_t t = fork();
/* create a child process */
if(t<0){
printf("error in fork");
exit(1);
}
/* create a pipe */
if(pipe(pd)==-1){
printf("error in pipe");
exit(3);
}
else if(t==0){
//close(pd[1]); // child close writing end
int r = read(pd[0], &num, sizeof(num));
if(r<0){
printf("error while reading");
exit(2);
}
printf("i am the child and i read %d\n",num);
// close(pd[0]);
exit(0);
}
/* parent process */
//close(pd[0]); /* parents closes its reading end
if(write(pd[1],&num,sizeof(num)<0)){
printf("error in reading");
exit(4);
}
//close(pd[1]);
/*parent wait for your child to terminate;*/
int status;
wait(&status);
printf("my child ended with status: %d\n",status);
return 0;
}
Try to play with close(). Skip it by putting it in a comment or include it. You will find out that in order this program to run the only really needed system-call close is the one before the child reads. I found here in stack overflow an answer saying that " Because the write-end is open the system waits because a potential write could occur .. " . Personally, I tried to run it without it and I discovered that it would not terminate. The other close(), although are a good practice , don't influence the execution. ( I am not sure why that happens maybe someone more experienced can help us).
Now let's examine what you asked:
I can see some problems here:
If two processes write in the same channel you may have race conditions:
They write to the same file descriptor at the same time:
What if one process reads its own writings instead of those of the process
it tries to communicate with? How you will know, where in the file you should read?
What if the one process, writes "above" the writings of the other?
Yes it can, I've done that before. I had a parent and child send each other different messages using the same 2 pipes and receive them correctly. Just make sure you're always reading from the first file descriptor and writing to the second.
In my below working program, I would like to understand,
How/who established(created) a single pipe communication between {child's pair[1]} descriptor and {parent's pair[0]} descriptor?
Because in my below program, i just fork()'d a process and immediately who has established pipe connection between {child's pair[1]} descriptor and {parent's pair[0]} descriptor? Do you think it is obvious to accept this point?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
int pair[2];
char buf[30] ="";
pipe(pair);
if (!fork()) {
printf(" CHILD: writing to the pipe\n");
write(pair[1], "test", 5);
printf(" CHILD: exiting\n");
exit(0);
} else {
printf("PARENT: reading from pipe\n");
read(pair[0], buf, 5);
wait(NULL);
printf(" PARENT: exiting\n");
}
return 0;
}
Please help me!!
Your questions are not particularly clear; the second "question" says something looks obvious, but appears to contain no question itself. For instance, you don't actually say what is going wrong in the samples you have presented (if anything).
I think what you what to know might be as follows:
pipe() creates two file descriptors which are linked within the operating system, a reader and a writer.
When you fork() all open FDs are available in both the parent and the child. So if you have called pipe() prior to the fork(), both the reader and the writer will be available to the child.
As normally the parent will be the reader and the child the writer, or the parent will be the writer and the child the reader (i.e. neither will both write and read), it is normal for the parent to close one fd and the child to close the other.
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.