1. Great video 2. In response to your question: returning different values is convenient, easy to debug and understand, so for video purposes it may be a good idea to keep it as it is. But speaking of error handling - plain return statement may be not the best choice for more complex applications. So if I may, I'd like to suggest creating a video about error handling alternative approaches. We know that C does not support exceptions that we know form Java and C++, so it would be nice to have something instead. All the best!
Some ideas that come to my mind: 1) Have a list of macros defining IDs for different errors (e.g.: #define ERR_PIPE_CREATION_FAILED 0 #define ERR_CHILD_NOT_RUNNING 1 ...). enums instead of macros could work as well 2) Build a function that receives as parameter one of the previous error codes / IDs and handles it as needed (printing, closing pipes, killing threads, freeing dynamic memory, ..., and finally killing the current process). The problem I see with this approach is that the error handler function would need access to those elements to close/kill/free. And make them global could be tricky for large applications. Any other method / drawbacks are welcomed
About the same line brackets, my thinking is if the code can be read like a sentence left to right I'll make it one line. I always summarize the functionality of inner code blocks when ingesting code, and whenever a code blocks a one liner I can save myself the effort in trying to remember what that code block does and interpret it literally instead of trying to remember what the summary of the high level functionality is
Great explanation, Thank you this is a good example of producer consumer problem with 2 processes with pipe() . could you please create a video explaining Multiple process producers and multiple process consumers using pipe()?
Imho, it s clear and easy to follow your return values for the syscalls. I prefer using a macro to check the return value for syscalls because i like to also print why did the call failed.
Yes, that's a good idea! I may make a video on this topic, it really cuts down on the amount of code you need to write. Either way, it's very important to check the result of syscalls, otherwise your program might fail unexpectedly.
On freeBSD it seems to always work fine with a single pipe. Regarding your question, I have made a function in another file with its header. You enter what read(), write(), etc... returns and the name of the function that generated it and prints out the error and executes the exit if it is -1 or, otherwise, prints out that the function has been executed. successfully executed.
Hey, great video, i'm viewing this to repeat pipes for my univeristy exam, so, about bidirectional communication, i think that another reason becouse it work (with 2 pipes), is becouse the read syscall is a blocking operation, so if there isn't nothing to read the process wait unitil something is writted, is true? Thanks a lot, you earn a new subscriber!
Would another solution not be to put the wait() right after the parent writes the randomly generated number to the pipe? So it would have to wait for the child process to calculate the value, then it is allowed to read it
Yes, I thought so too and tried it, it works as long as you terminate the child after it has written to the parent. Although I think there's a reason why you should use 2 pipes because I saw someone say it somewhere else as well but the reason why.. I don't know.
Great video! I wish that during the parts where the terminal result is not relevant, you would close it so we can see more of the code (helps process what is going on overall better). Or zoom out a bit so we can see more lines of code at once.
Sockets are bi-directional and can be created as byte streams or datagram sequences while pipes can only be byte streams. Another aspect is that pipes are half-duplex, meaning you can't send and receive data at the same time
@@amaz404 Pipes are generally faster than sockets on the same machine (on certain OSes). On Linux, they seem to have the same performance, so some people recommend just using sockets. Here's a few links you can read: home.iae.nl/users/mhx/pipes&socks.html stackoverflow.com/questions/1882886/performance-of-sockets-vs-pipes
Yes, could work if you control the order of execution of processes with just one pipe... but usually it's better practice to just use 1 pipe per child process.
Now it's starting to make sense why I can't pass a variable to an external program and read its output. Every time the C/C++ community talks about pipes they aren't actually talking about calling anything external. They are just talking about a way to pass values within their code. Wish I watched this video earlier, could have saved a couple of days.
hey, thank you soo much for the video. I was wondering instead of creating another pipe would it be possible to use the wait() function to have the parent wait for the child process to finish
Your videos are just amazing I have just a question , I tried to put wait(NULL) after the parent write to child and then the child recieved and make the calculation .... and when I add this wait() it worked , Can we use it like that without creating a new pipe or it could be a problem and we have to create a new pipe ??
This could be done but would only work for one read and write operation for the whole process. If you want to reuse the pipes (and the processes), you'd have to create 2 pipes
Write a C program that allows communication between two processes. Dec. Communication with the pipe must be provided. Process A must transmit the message it receives from the outside world as an argument to process B, process B it should also reverse the same message and send it to process A again. All this message communication is every transaction then it should be logged on the screen?
Question on closing the file descriptors, is there any reason why you couldn't close them all at the end? Is it good prectice? Or just for the clarity of the explanation? Thinking of doing a close_multiple_fd() to shorten the code a bit, good idea? Absolutely gorgeous videos btw, thanks am million for sharing your knowledge!
It's important to close the unused fd's before actually sending data through simply because, when reading, you only get an EOF after all writer fd's have been closed
How do we know which process will run first? As I know, the processes run at the same time. How do we know that the parent will run first and send the number to the child? And then the number will be multiplied and send back and only after that read? My guess is that read command in child wait for the input. So the write command in parent will run first and then read command in parent will wait for the input. So child has time to calculate and write data to the pipe. When the data is written and parent can read it, the read is executed. But what about other commands? Can we predict the order? Also, how necessary is wait() in this scenario? Why don't we put read after wait, will it not guarantee that the child process will read and write to this time?
wait() is for releasing any resources. Yes, you could call it before reading from the pipe but then you won't be able to read/write multiple times from the process. And yes, as you predicted, read() does wait for data to exist in the pipe(). This is fine as long as you have 1 reader and 1 writer and this is also why 1 pipe for two-way communications doesn't really work
Can you please create a video on how to do this in MQL4? Just a simple send and receive. I want to send information from one EA installed on a MetaTrader 4 'terminal A' to the EA installed on 'terminal B' (Both the terminals are on the same computer.)
Thank you for the great explanation. I'm writing a similar code, but instead of using " x *= 4 " in the child process, I need to execute another c program and use x as input and get the result back. How can I do that? I'll appreciate your help.
On Mac OS, however, I am seeing a slightly different behaviour, to make the parent wait for the child process without using two file descriptors p1 & p2, I had to put wait(NULL) statement right after writing to child in parent process only then it worked. And after adding the two separate file descriptors p1 & p2, even if I remove wait(NULL) statement it worked perfectly.
@@CodeVault this code seems to work on macos: #include #include #include int main(void) { /* Program objective: Parent writes an integer, child reads it */ /* Child multiplies it by 4, parent reads the new number */ /* Interest: Bidirectional communication with pipes */ /* Another way to achieve this is by using two pipes. One for data transfer Parent->Child */ /* and the other for data transfer Child->Parent. It seems to work with a single pipe on macOS, but */ /* it doesn't seem to work on other operating systems. */ int fd[2]; if (pipe(fd) == -1) { return 1; } int pid = fork(); if (pid == -1) { return 2; } else if (pid == 0) { /* Child process code */ int x; /* No need for wait because read waits */ /* for data to be written to the pipe */ if (read(fd[0], &x, sizeof(x)) == -1) { return 3; } printf("Here is the child process, I read %d from the pipe. ", x); x = 4 * x; if (write(fd[1], &x, sizeof(x)) == -1) { return 4; } printf("Here is the child process, I wrote %d to the pipe. ", x); close(fd[0]); close(fd[1]); printf("Here is the child. Goodbye. "); } else { /* Parent process code */ int y1, y2; printf("Enter an integer: "); scanf("%d", &y1); if (write(fd[1], &y1, sizeof(y1)) == -1) { return 5; } printf("Here is the parent process, I wrote %d to the pipe. ", y1); wait(NULL); /* Wait for the child process to finish execution */ if (read(fd[0], &y2, sizeof(y2)) == -1) { return 6; } printf("Here is the parent process, I read %d from the pipe. ", y2); close(fd[0]); close(fd[1]); } return 0; }
Sir here the child process should wait till the parent process writes some value to the pipe so that the child process can take that value and modify. But where in the program are we ensuring this condition ??
It's an intrinsic property of the read call. Basically when you read from a pipe, that read call will wait until there is something to read in that pipe. Similarly a write call will wait until there is space to write to that pipe (the pipe's buffer in this case)
@@CodeVault I think you should put this answer on the description or somewhere because I directly looked for this question after I watched the video. Btw it was a great video again, congrats!
If you did the "homework" from the previous video in the series, you could have faced a similar problem depending on your implementation. I did that homework with 1 parent having two children, and each process then summing up a section of the array, and then writing it to a pipe, where the parent was supposed to read from. But then I realised, if I only create one pipe before forking, what if the two children write to the pipe at the same time? What if one finished writing but the other not, then what would happen to the read() call in parent? So just to be safe I created a second pipe, so the two children would connect to the parent with different pipes. This way the parent would read from different pipes into different buffers. I never found out the answer to the what if situations tho.
I did some research regarding your questions. Regarding your 1st question: For the most part having 2 processes write on the same pipe shouldn't be a problem unless the messages are smaller than PIPE_BUF bytes. The messages shouldn't interleave. Although there are situations where the write call has written at least 1 byte in the pipe and is interrupted. At that point the write() call returns a number of bytes written less than expected and it could be difficult to fix on the read() end. Regarding the 2nd question: If one process finished writing then the read() call should already succeed regardless of the second process' write() Still, the solution you ended up implementing, having two pipes, one for each child process is much more reliable
@@CodeVault Cool, thanks for answering! Regarding case1: I never even though about the size of the pipe buffer, but if you want to send only small amounts of data, then you would always face issues, right? I read that you can adjust the pipe buf size with fcntl(), thought I'm not sure as I never needed it. And case2: I'm not sure what you mean, do you mean read() only waits for the 1st write to finish? For me that's sounds logical. So then you would need two reads in the parent. Well in any case, using two pipes seems to be safer and simpler. EDIT: regarding case2: nvm, I read the pipe() man page, and it seems like it is only true if the pipe is widowed. Well the pipe should be widowed anyway, but the man page says that you can still use the F_SETNOSIGPIPE in fcntl(), which would mean the the writing process wouldn't deliver EOF to the reader, meaning the read would keep reading forever, as now none of the writes send the EOF. So one of them should send it to read(), but then the one that sends it would need to be the one that writes last, meaning now the 2nd child has to wait for the 1st child, which would make the whole exercise pointless, as you would lose the benefits of multiple processes calculating at the same time...
if the pipe is empty the read() call waits for someone to write in the pipe with write() ? shouldnt it return a error value since it tries to read something that doesn't exits?
@@CodeVault like u said read wait until their is something to read so in one pipe when parent write and read it immediately so it will get over but the child will also read it calculate it and write it we will not get the correct result as parent process getfinish first but it should not get stuck also why it is getting stuck?
is this work if we put wait call in else part on next line where y was written so then parent has to wait to terminate child process so now only child process can read y ?(i am taking about the code written before p2 was introduce)
so read() waits till the pipe is filled once with some data? or how does the parent read() knows the child process has already written in it. am i correct? :)
does it work if instead of creating 2 pipes i make parent wait until child write down the result and then parent reads it. & your videos are great really really helpful. thankyou
#include #include #include #include int main(int argc, char *argv[]) { int p1[2]; if(pipe(p1) == -1) { printf("An error occured while opening pipe. "); return 1; } int pid = fork(); if(pid == 0) { //child process int x; printf(" Child: Waiting to receive value from parent. "); if(read(p1[0], &x, sizeof(x)) == -1) { printf("Child: An error occured while reading from pipe. "); return 2; } close(p1[0]); printf("Child: Received %d. ", x); x *= 10; printf("Child: Processing value. "); if(write(p1[1], &x, sizeof(x)) == -1) { printf("Child: An error occured while writing in pipe. "); return 3; } close(p1[1]); printf("Child: Wrote down the result. "); } else { //parent process int n; printf(" Parent: Enter a number - "); scanf("%d", &n); printf("Parent: Writing value entered by user. "); if(write(p1[1], &n, sizeof(n)) == -1) { printf("Parent: An error occured while writing in pipe. "); return 4; } printf("Parent: Wrote down the value. "); close(p1[1]); printf("Parent: Waiting for child to finish processing. "); wait(NULL); if(read(p1[0], &n, sizeof(n)) == -1) { printf("Parent: An error occured while reading from pipe. "); return 5; } printf("Parent: Number returned from child - %d ", n); close(p1[0]); } return 0; } this is working fine for me does this have have a corner case that i am missing.
Hmm, I think this approach will work. The only problem is, you can only send data back to the parent once, since, you have to end the process afterwards. With 2 pipes you can continue sending as much data as you want.
@@CodeVault So pipe before fork means that you have 1 pipe, right? Same in both: in the child and int the parent, right? In my project I used one pipe before forking and then could close both ends (open, write) in the child and in the parent process (it means 4 of close()). How did it work? if it the same pipe. When the pipes fds are closed, how they can be still available in the parent?
Hi if the child process closes the write(fd[1]) of a pipe and I want the parent process to be able to detect when it is closed -> do something , how do I do that? Thabks
@@CodeVault But when I did this , I was unable to receive anything from check or print it and it is unable to enter the if statement. Many thanks. else if (pid > 0) { read(fd[0],buf,BUFSIZE); printf("%s cpid: %d ppid: %d ",buf,cpid,getpid()); while(1) { int check = read(fd[0],fub,BUFSIZE); printf("%d ",check); if(check < 1) { printf("Parent process pid:%d is terminating.. ",getpid()); exit(0); } sleep(1); } }
in the part when you comment the printf("wrote %d ", y); in the parent process I try to use wait before read in the parent process and with this even i comment the printf("wrote %d ", y); I found the same output without any problem what do you think is a good idea?! int main() { int p1[2]; int pid; if (pipe(p1) == -1 ) return 1; pid = fork(); if (pid == -1) return 2; if (pid == 0) { int x; if (read(p1[0], &x, sizeof(x)) == -1) return 3; printf("in child : Received %d ", x); x *= 4; if (write(p1[1], &x, sizeof(x)) == -1) return 4; printf("in child : Wrote %d ", x); } else { srand(time(NULL)); int y = rand() % 10; if (write(p1[1], &y, sizeof(y)) == -1) return 5; // printf("in parent : Wrote %d ", y); wait(NULL); if (read(p1[0], &y, sizeof(y)) == -1) return 6; printf("Result is %d ", y); } close(p1[0]); close(p1[1]); return (0); }
Yes. That works if you absolutely want to use one pipe. There are two issues with the code though: 1) You have to wait for the child process to finish execution (might lose performance if the child process does some CPU intensive work after writing to the pipe) 2) This only works once... If you want to read/write multiple times, you will need a second pipe. This is why I recommend using 2 pipes for two-way communication
Uhm, I'm not sure what you're trying to achieve here. You'd need to change the underlying code from stockfish to communicate between it and your own process I think.
@@CodeVault i am trying to achieve inter process communication between c++ and stockfish to predict best chess moves....so, i am currently thinking to create two half-duplex UNIX pipes with pipe() fork() dup2() exec(), one for stdout of program => stdin of chess-engine and vice versa for the other. Hope this can work for me. I am learning these concepts now. Btw, thanks for the reply!
@@CodeVault Thanks, I will. I did try to debug my broken pipes using gdb when I analyzed breakpoints at write functions but was struggling to understand the output. Maybe there is a way to make it more visual. Would you make a video on gdb?
I'm amazed by this power you have to explain complex stuff like this in such short videos. I've watched almost every single one of them. thanks!
you are the best! you taught me this better than my university prof
Relatable ahhahahahaha
I like the return statements in the same line, makes it cleaner and easier to follow. Ty for the great videos.
1. Great video
2. In response to your question: returning different values is convenient, easy to debug and understand, so for video purposes it may be a good idea to keep it as it is.
But speaking of error handling - plain return statement may be not the best choice for more complex applications. So if I may, I'd like to suggest creating a video about error handling alternative approaches. We know that C does not support exceptions that we know form Java and C++, so it would be nice to have something instead.
All the best!
I've seen some nice approaches to error handling in C. Will certainly research this further. Thanks for the feedback! Helps a lot!
Some ideas that come to my mind:
1) Have a list of macros defining IDs for different errors (e.g.:
#define ERR_PIPE_CREATION_FAILED 0
#define ERR_CHILD_NOT_RUNNING 1
...). enums instead of macros could work as well
2) Build a function that receives as parameter one of the previous error codes / IDs and handles it as needed (printing, closing pipes, killing threads, freeing dynamic memory, ..., and finally killing the current process).
The problem I see with this approach is that the error handler function would need access to those elements to close/kill/free. And make them global could be tricky for large applications. Any other method / drawbacks are welcomed
Thank you so much! Your C language videos are saving me in my university courses.
I am so lucky to have found this channel. Just amazing!!
Awesome video. He explains a lot of stuff in as short as 10-20 mins. Great job. We're looking to see more content from you
THANK YOU SO MUCH! You are helping me get through my operating systems class haha This has helped a lot :)
You look like the nerd of the class.
Amazingly explained. love ya
Always am, always will be :D
Im impressed , amazing job, finally i understand how pipes work.
Please make videos on Pthreads. Your teaching is very nice.
About the same line brackets, my thinking is if the code can be read like a sentence left to right I'll make it one line.
I always summarize the functionality of inner code blocks when ingesting code, and whenever a code blocks a one liner I can save myself the effort in trying to remember what that code block does and interpret it literally instead of trying to remember what the summary of the high level functionality is
Great explanation, Thank you
this is a good example of producer consumer problem with 2 processes with pipe() . could you please create a video explaining Multiple process producers and multiple process consumers using pipe()?
Imho, it s clear and easy to follow your return values for the syscalls. I prefer using a macro to check the return value for syscalls because i like to also print why did the call failed.
Yes, that's a good idea! I may make a video on this topic, it really cuts down on the amount of code you need to write. Either way, it's very important to check the result of syscalls, otherwise your program might fail unexpectedly.
On freeBSD it seems to always work fine with a single pipe.
Regarding your question, I have made a function in another file with its header.
You enter what read(), write(), etc... returns and the name of the function that generated it and prints out the error and executes the exit if it is -1 or, otherwise, prints out that the function has been executed. successfully executed.
this really helped me understand this concept, thank you very much!
so amezing, i got similar assignment, thanks for help, i am watching whole playlist now.
criminally underrated
You are doing an awesome job. Keep going & post more videos of such!! :)
Hey, great video, i'm viewing this to repeat pipes for my univeristy exam, so, about bidirectional communication, i think that another reason becouse it work (with 2 pipes), is becouse the read syscall is a blocking operation, so if there isn't nothing to read the process wait unitil something is writted, is true?
Thanks a lot, you earn a new subscriber!
Thanks a lot!!
did the Fifo video of two-way communication already up?
Hmm, it seems I never got around to making it. The idea is exactly the same as in this video but instead of opening 2 pipes you open 2 different fifos
Would another solution not be to put the wait() right after the parent writes the randomly generated number to the pipe? So it would have to wait for the child process to calculate the value, then it is allowed to read it
Yes, I thought so too and tried it, it works as long as you terminate the child after it has written to the parent. Although I think there's a reason why you should use 2 pipes because I saw someone say it somewhere else as well but the reason why.. I don't know.
Great video! I wish that during the parts where the terminal result is not relevant, you would close it so we can see more of the code (helps process what is going on overall better). Or zoom out a bit so we can see more lines of code at once.
Thanks for the feedback, I'll keep that in mind
Awesome video! Thank you so much!
I love your videos - they are very clear! Is there an advantage to using two pipes vs using a unix domain socket instead?
Sockets are bi-directional and can be created as byte streams or datagram sequences while pipes can only be byte streams. Another aspect is that pipes are half-duplex, meaning you can't send and receive data at the same time
@@CodeVault so is there any advantage to using two pipes? It seems that it is much easier to just use a socket
@@amaz404 Pipes are generally faster than sockets on the same machine (on certain OSes). On Linux, they seem to have the same performance, so some people recommend just using sockets. Here's a few links you can read:
home.iae.nl/users/mhx/pipes&socks.html
stackoverflow.com/questions/1882886/performance-of-sockets-vs-pipes
@@CodeVault Thank you!
amazingly explained!
Would it work if instead of using 2 pipes, we would put a wait() in the parent process right after we generate and write the number?
Yes, could work if you control the order of execution of processes with just one pipe... but usually it's better practice to just use 1 pipe per child process.
@@CodeVault Don't we have only one child process here, or am I am misunderstanding something?
Now it's starting to make sense why I can't pass a variable to an external program and read its output. Every time the C/C++ community talks about pipes they aren't actually talking about calling anything external. They are just talking about a way to pass values within their code. Wish I watched this video earlier, could have saved a couple of days.
Superb material.
hey, thank you soo much for the video. I was wondering instead of creating another pipe would it be possible to use the wait() function to have the parent wait for the child process to finish
Yes but then the pipe can only be used once
Your videos are just amazing I have just a question , I tried to put wait(NULL) after the parent write to child and then the child recieved and make the calculation ....
and when I add this wait() it worked , Can we use it like that without creating a new pipe or it could be a problem and we have to create a new pipe ??
This could be done but would only work for one read and write operation for the whole process. If you want to reuse the pipes (and the processes), you'd have to create 2 pipes
you are awesome. many many thanks from german :)
You are the best, thank so so much
Write a C program that allows communication between two processes. Dec. Communication with the pipe
must be provided. Process A must transmit the message it receives from the outside world as an argument to process B, process B
it should also reverse the same message and send it to process A again. All this message communication is every transaction
then it should be logged on the screen?
Great video!! Thank you so much!
Question on closing the file descriptors, is there any reason why you couldn't close them all at the end? Is it good prectice? Or just for the clarity of the explanation? Thinking of doing a close_multiple_fd() to shorten the code a bit, good idea? Absolutely gorgeous videos btw, thanks am million for sharing your knowledge!
It's important to close the unused fd's before actually sending data through simply because, when reading, you only get an EOF after all writer fd's have been closed
Amazing as always
Good video. Thank you. A little bit lost with p1 and p2. It will be better to remain like CP and PC.
Thank you so much! you saved me
you are awesome in teaching
thanks god that you exist
Thank you bhaiya
How do we know which process will run first? As I know, the processes run at the same time. How do we know that the parent will run first and send the number to the child? And then the number will be multiplied and send back and only after that read?
My guess is that read command in child wait for the input. So the write command in parent will run first and then read command in parent will wait for the input. So child has time to calculate and write data to the pipe. When the data is written and parent can read it, the read is executed.
But what about other commands? Can we predict the order?
Also, how necessary is wait() in this scenario? Why don't we put read after wait, will it not guarantee that the child process will read and write to this time?
wait() is for releasing any resources. Yes, you could call it before reading from the pipe but then you won't be able to read/write multiple times from the process.
And yes, as you predicted, read() does wait for data to exist in the pipe(). This is fine as long as you have 1 reader and 1 writer and this is also why 1 pipe for two-way communications doesn't really work
@1:58 - I would even skip the curly brackets in my projects in case there is only 1 instruction after "if" for more clarity ;-)
I never skip them for consistency's sake. Also when adding more lines there it doesn't brick my code. Everyone has their own style
Can you please create a video on how to do this in MQL4? Just a simple send and receive. I want to send information from one EA installed on a MetaTrader 4 'terminal A' to the EA installed on 'terminal B' (Both the terminals are on the same computer.)
I will look into
Thank you for the great explanation. I'm writing a similar code, but instead of using " x *= 4 " in the child process, I need to execute another c program and use x as input and get the result back. How can I do that? I'll appreciate your help.
There's this video on the topic, hope it helps: code-vault.net/lesson/oxyoxbvnak:1603732432935
On Mac OS, however, I am seeing a slightly different behaviour, to make the parent wait for the child process without using two file descriptors p1 & p2, I had to put wait(NULL) statement right after writing to child in parent process only then it worked. And after adding the two separate file descriptors p1 & p2, even if I remove wait(NULL) statement it worked perfectly.
Can you please share the exact code you tried? I would like to test this to understand the difference
@@CodeVault
#include
#include
#include
#include
#include
int main(int argc, const char * argv[]) {
// insert code here...
int p1[2]; //Child to parent pipe
int p2[2]; //Parent to child pipe
if(pipe(p1) == -1){
printf("Error opening pipe");
return 1;
}
if(pipe(p2) == -1){
printf("Error opening pipe");
return 1;
}
int pid = fork();
if(pid == -1)
{
printf("Error getting process ID");
return 2;
}
if(pid == 0) // Child Process
{
close(p1[0]);
close(p2[1]);
int x;
if(read(p2[0], &x,sizeof(x)) == -1)
{
printf("Error reading from pipe");
return 3;
}
printf("Received from parent process: %d
", x);
x*=4;
if(write(p1[1], &x,sizeof(x)) == -1)
{
printf("Error writing parent process through pipe");
return 4;
}printf("Wrote to parent process: %d
", x);
close(p1[1]);
close(p2[0]);
}
else{
close(p1[1]);
close(p2[0]);
srand(time(NULL)); //Parent Process
int y = rand()%10;
if(write(p2[1], &y,sizeof(y)) == -1)
{
printf("Error writing to child process through pipe");
return 5;
}
printf("Wrote to child process: %d
", y);
// wait(NULL);
if(read(p1[0], &y,sizeof(y)) == -1)
{
printf("Error reading from pipe");
return 6;
}
printf("Received from child process: %d
", y);
//wait(NULL);
close(p1[0]);
close(p2[1]);
}
return 0;
}
@@CodeVault this code seems to work on macos:
#include
#include
#include
int main(void) {
/* Program objective: Parent writes an integer, child reads it */
/* Child multiplies it by 4, parent reads the new number */
/* Interest: Bidirectional communication with pipes */
/* Another way to achieve this is by using two pipes. One for data transfer Parent->Child */
/* and the other for data transfer Child->Parent. It seems to work with a single pipe on macOS, but */
/* it doesn't seem to work on other operating systems. */
int fd[2];
if (pipe(fd) == -1) {
return 1;
}
int pid = fork();
if (pid == -1) {
return 2;
}
else if (pid == 0) {
/* Child process code */
int x;
/* No need for wait because read waits */
/* for data to be written to the pipe */
if (read(fd[0], &x, sizeof(x)) == -1) {
return 3;
} printf("Here is the child process, I read %d from the pipe.
", x);
x = 4 * x;
if (write(fd[1], &x, sizeof(x)) == -1) {
return 4;
} printf("Here is the child process, I wrote %d to the pipe.
", x);
close(fd[0]); close(fd[1]);
printf("Here is the child. Goodbye.
");
}
else {
/* Parent process code */
int y1, y2;
printf("Enter an integer: ");
scanf("%d", &y1);
if (write(fd[1], &y1, sizeof(y1)) == -1) {
return 5;
} printf("Here is the parent process, I wrote %d to the pipe.
", y1);
wait(NULL); /* Wait for the child process to finish execution */
if (read(fd[0], &y2, sizeof(y2)) == -1) {
return 6;
} printf("Here is the parent process, I read %d from the pipe.
", y2);
close(fd[0]); close(fd[1]);
}
return 0;
}
Sir here the child process should wait till the parent process writes some value to the pipe so that the child process can take that value and modify. But where in the program are we ensuring this condition ??
It's an intrinsic property of the read call. Basically when you read from a pipe, that read call will wait until there is something to read in that pipe. Similarly a write call will wait until there is space to write to that pipe (the pipe's buffer in this case)
@@CodeVault I think you should put this answer on the description or somewhere because I directly looked for this question after I watched the video. Btw it was a great video again, congrats!
amazing!!!
How are you using unistd.h in vscode? Are you on Linux? Is it possible to use on Windows10?
unistd.h is Unix specific. In these videos I use Linux, you could also achieve the same thing with WSL on Windows
Could we just use wait(NULL) in place of commented printf()?
I didn't tested it myself
This would work but only for one read/write operation. If you want more than that (which is usually the case) you will need multiple pipes
@@CodeVault Ah, makes sense!
Thanks!
Should pipe be created of the same type of data we want to send ?
Pipes don't have the concept of types so you don't have to worry about that
For this one, is it possible to do it with dup()? I'm actually very confused when and how to use dup()
dup() is only needed for replacing file descriptors with other existing ones. I don't think you need dup() for this
What's the use of srand(time(NULL)); in this program?
It's for seeding the random numbers. Here's an explanation of why you need it alongside rand(): code-vault.net/lesson/9p823km0sm:1603733520459
@@CodeVault thank you so much
If you did the "homework" from the previous video in the series, you could have faced a similar problem depending on your implementation.
I did that homework with 1 parent having two children, and each process then summing up a section of the array, and then writing it to a pipe, where the parent was supposed to read from. But then I realised, if I only create one pipe before forking, what if the two children write to the pipe at the same time? What if one finished writing but the other not, then what would happen to the read() call in parent?
So just to be safe I created a second pipe, so the two children would connect to the parent with different pipes. This way the parent would read from different pipes into different buffers.
I never found out the answer to the what if situations tho.
I did some research regarding your questions.
Regarding your 1st question:
For the most part having 2 processes write on the same pipe shouldn't be a problem unless the messages are smaller than PIPE_BUF bytes. The messages shouldn't interleave. Although there are situations where the write call has written at least 1 byte in the pipe and is interrupted. At that point the write() call returns a number of bytes written less than expected and it could be difficult to fix on the read() end.
Regarding the 2nd question:
If one process finished writing then the read() call should already succeed regardless of the second process' write()
Still, the solution you ended up implementing, having two pipes, one for each child process is much more reliable
@@CodeVault Cool, thanks for answering!
Regarding case1: I never even though about the size of the pipe buffer, but if you want to send only small amounts of data, then you would always face issues, right? I read that you can adjust the pipe buf size with fcntl(), thought I'm not sure as I never needed it.
And case2: I'm not sure what you mean, do you mean read() only waits for the 1st write to finish? For me that's sounds logical. So then you would need two reads in the parent.
Well in any case, using two pipes seems to be safer and simpler.
EDIT: regarding case2: nvm, I read the pipe() man page, and it seems like it is only true if the pipe is widowed. Well the pipe should be widowed anyway, but the man page says that you can still use the F_SETNOSIGPIPE in fcntl(), which would mean the the writing process wouldn't deliver EOF to the reader, meaning the read would keep reading forever, as now none of the writes send the EOF. So one of them should send it to read(), but then the one that sends it would need to be the one that writes last, meaning now the 2nd child has to wait for the 1st child, which would make the whole exercise pointless, as you would lose the benefits of multiple processes calculating at the same time...
could you please explain how to communicate between two programs?
In this video I explain how to do that: code-vault.net/lesson/oxyoxbvnak:1603732432935
if the pipe is empty the read() call waits for someone to write in the pipe with write() ?
shouldnt it return a error value since it tries to read something that doesn't exits?
No, when you call "read()", the process waits until there's something to read while the write end is still opened somewhere
@@CodeVault like u said read wait until their is something to read
so in one pipe when parent write and read it immediately so it will get over but the child will also read it calculate it and write it
we will not get the correct result as parent process getfinish first but it should not get stuck also why it is getting stuck?
правильно я понял что 1 pipe лучше использовать для связи в одну сторону, а для связи в другую сторону нужен второй pipes ?
Yes, pipes were designed to only be used for one way communication
is this work if we put wait call in else part on next line where y was written so then parent has to wait to terminate child process so now only child process can read y ?(i am taking about the code written before p2 was introduce)
I'm not sure what you mean... the wait call can be placed anywhere in the parent as read/write operations are blocking
so read() waits till the pipe is filled once with some data? or how does the parent read() knows the child process has already written in it. am i correct? :)
Yes, read() waits for data to be in the pipe and write() waits for there to be enough space in the buffer to write to
@@CodeVault oh man, thx for the fast answer :)
does it work if instead of creating 2 pipes i make parent wait until child write down the result and then parent reads it. & your videos are great really really helpful. thankyou
#include
#include
#include
#include
int main(int argc, char *argv[])
{
int p1[2];
if(pipe(p1) == -1)
{
printf("An error occured while opening pipe.
");
return 1;
}
int pid = fork();
if(pid == 0)
{
//child process
int x;
printf("
Child: Waiting to receive value from parent.
");
if(read(p1[0], &x, sizeof(x)) == -1)
{
printf("Child: An error occured while reading from pipe.
");
return 2;
}
close(p1[0]);
printf("Child: Received %d.
", x);
x *= 10;
printf("Child: Processing value.
");
if(write(p1[1], &x, sizeof(x)) == -1)
{
printf("Child: An error occured while writing in pipe.
");
return 3;
}
close(p1[1]);
printf("Child: Wrote down the result.
");
}
else
{
//parent process
int n;
printf("
Parent: Enter a number - ");
scanf("%d", &n);
printf("Parent: Writing value entered by user.
");
if(write(p1[1], &n, sizeof(n)) == -1)
{
printf("Parent: An error occured while writing in pipe.
");
return 4;
}
printf("Parent: Wrote down the value.
");
close(p1[1]);
printf("Parent: Waiting for child to finish processing.
");
wait(NULL);
if(read(p1[0], &n, sizeof(n)) == -1)
{
printf("Parent: An error occured while reading from pipe.
");
return 5;
}
printf("Parent: Number returned from child - %d
", n);
close(p1[0]);
}
return 0;
}
this is working fine for me does this have have a corner case that i am missing.
Hmm, I think this approach will work. The only problem is, you can only send data back to the parent once, since, you have to end the process afterwards. With 2 pipes you can continue sending as much data as you want.
How to implement this in Windows?What are the procedure?
You'll have to use the Win32 API for that which quite a bit different than this: docs.microsoft.com/en-us/windows/win32/ipc/anonymous-pipe-operations
Hi, how can we be sure that the parent writes before the child starts to read with respect to p2?
You don't need to. The read() function waits until there is something written in the pipe's buffer
Thank you. I had this same question
if you fork after the pipe, does it not mean that you have two pipes: one in child and one in parent as all the variables are duplicated?
No. The file handlers are being copied on forking. If you call pipe() after fork() you end up with 2 separate pipes
@@CodeVault So pipe before fork means that you have 1 pipe, right? Same in both: in the child and int the parent, right?
In my project I used one pipe before forking and then could close both ends (open, write) in the child and in the parent process (it means 4 of close()). How did it work? if it the same pipe. When the pipes fds are closed, how they can be still available in the parent?
Whenever you close the fds, it only closes for that specific process. The fds on the other process remain untouched
Hi if the child process closes the write(fd[1]) of a pipe and I want the parent process to be able to detect when it is closed -> do something , how do I do that? Thabks
If all pipe write ends are closed an EOF is emitted on the read ends
@@CodeVault no all ends closed, just the writing end.
yes, just the write end
@@CodeVault
But when I did this , I was unable to receive anything from check or print it and it is unable to enter the if statement. Many thanks.
else if (pid > 0)
{
read(fd[0],buf,BUFSIZE);
printf("%s cpid: %d ppid: %d
",buf,cpid,getpid());
while(1)
{
int check = read(fd[0],fub,BUFSIZE);
printf("%d
",check);
if(check < 1)
{
printf("Parent process pid:%d is terminating..
",getpid());
exit(0);
}
sleep(1);
}
}
You forgot to close fd[1] in the parent process
in the part when you comment the printf("wrote %d
", y); in the parent process I try to use wait before read in the parent process and with this even i comment the printf("wrote %d
", y); I found the same output without any problem what do you think is a good idea?!
int main()
{
int p1[2];
int pid;
if (pipe(p1) == -1 ) return 1;
pid = fork();
if (pid == -1) return 2;
if (pid == 0)
{
int x;
if (read(p1[0], &x, sizeof(x)) == -1) return 3;
printf("in child : Received %d
", x);
x *= 4;
if (write(p1[1], &x, sizeof(x)) == -1) return 4;
printf("in child : Wrote %d
", x);
}
else
{
srand(time(NULL));
int y = rand() % 10;
if (write(p1[1], &y, sizeof(y)) == -1) return 5;
// printf("in parent : Wrote %d
", y);
wait(NULL);
if (read(p1[0], &y, sizeof(y)) == -1) return 6;
printf("Result is %d
", y);
}
close(p1[0]);
close(p1[1]);
return (0);
}
Yes. That works if you absolutely want to use one pipe. There are two issues with the code though:
1) You have to wait for the child process to finish execution (might lose performance if the child process does some CPU intensive work after writing to the pipe)
2) This only works once... If you want to read/write multiple times, you will need a second pipe.
This is why I recommend using 2 pipes for two-way communication
@@CodeVault yeah thanks a lot You're a right
Can we just wait(NULL) right after write() in the parent process
Yes, you could. Although that would prevent you from reading and writing anything else between the processes
thanks for the video i have a problem i made an example like you why it gives different and big numbers for the child
Double check that you are sending and receiving the right amount of bytes
Its better to understand it like this 1:50
What is the software ur using ??
Visual Studio Code
I am confused if this can this be used to communicate between c++ and stockfish chess engine?
Uhm, I'm not sure what you're trying to achieve here. You'd need to change the underlying code from stockfish to communicate between it and your own process I think.
@@CodeVault i am trying to achieve inter process communication between c++ and stockfish to predict best chess moves....so, i am currently thinking to create two half-duplex UNIX pipes with pipe() fork() dup2() exec(), one for stdout of program => stdin of chess-engine and vice versa for the other. Hope this can work for me.
I am learning these concepts now. Btw, thanks for the reply!
Why do you create the fork after creating the pipes? Does that create 4 different children?
If you create the pipes after forking, you will end up with 2 different pipes that are not connected by anything. You can actually give this a try
@@CodeVault Thanks, I will. I did try to debug my broken pipes using gdb when I analyzed breakpoints at write functions but was struggling to understand the output. Maybe there is a way to make it more visual. Would you make a video on gdb?
#include
#include
#include
int main(int *argc, char *argv[]){
int pf1[2];
int pf2[2];
if(pipe(pf1)==-1){
return 1;
}
if(pipe(pf2)==-1){
reuturn 1;
}
int pid=fork();
if(pid==--1){
return 2;
}
if(pid==0){
close(pf1[0]);
close(pf2[1]);
//child process
int x;
read(pf1[0],&x,sizeof(x)==-1){return 3;
}
printf("recieved %d
",x);
x*=4;
if(write(pf2[1],&x,sizeof(x))==-1)
{
return 4;
}
printf("wrote %d
",x);
close(pf1[1]);
close(pf2[0]);
}
else{
close(pf1[1]);
close(pf2[0]);
srand(time(NULL));
int y=rand()%10;
if(write(pf2[1],&y,sizeof(y))==-1){
return 5;
}
if(read(pf1[0],&y,sizeof(y))==-1){
return 6;
}
printf("Result is %d
",y);
close(pf1[0]);
close(pf2[1]);
}
}