so I am new to inter-process communications and processes in linux, so I really cannot figure out what the problem is. The following program I wrote is the same problem I am having on a homework assignment consisting of using pipes condensed down. It is basically sending one character from the child to the parent, but it does not print out the character.
it print out:
hello from child
sending a
hello from parent
trying to receive...
received: reaping child
where on the third line it should say
received: a
Any answers are appreciated, and also if you have any helpful criticism of anything else in the program. Thanks everyone
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
pid_t pid = fork();
int comm[2];
pipe(comm);
if (pid == 0)
{
char send = 'a';
int check;
close(comm[0]);
printf("hello from child\n");
printf("sending %c\n", send);
check = write(comm[1], &send, 1);
printf("%d\n", check);
exit(1);
}
else if (pid > 0)
{
char get = ' ';
int check;
close(comm[1]);
printf("hello from parent\n");
printf("trying to receive...\n");
read(comm[0], &get, 2);
printf("received: %c\n", get);
printf("reaping child\n");
wait(NULL);
return 0;
}
return 0;
}
You got the pipe and the fork in the wrong order! Your process forks, then both processes call pipe, so 2 separate pipes are being created. The one you're writing into has nobody reading it, and the one you're reading from had nothing written to it.
Related
This is a C program where the Parent process tries to write a message to its child process using a simple pipe. The expected output is obtained.
According to the code, the parent calls wait() and waits until the child process exits(returns).
Also, the child process calls read(), which waits for something to be written through the other pipe end?
Thus, shouldn't both processes keep waiting for each other and cause a deadlock? How is it possible that the program works properly?
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#define MSGSIZE 16
char *msg1 = "Hello,Once";
char *msg2 = "Hello,Twice";
char *msg3 = "Hello,Thrice";
int main()
{
char buff[MSGSIZE];
int pi[2],pid,nbytes;
if(pipe(pi) < 0) _exit(1);
if((pid=fork()) > 0)
{
close(pi[0]);
write(pi[1],msg1,MSGSIZE);
write(pi[1],msg2,MSGSIZE);
write(pi[1],msg3,MSGSIZE);
close(pi[1]);
wait(NULL);
}
else
{
close(pi[1]);
while((nbytes = read(pi[0],buff,MSGSIZE)) > 0) printf("%s\n",buff);
printf("Reading Completed\n");
close(pi[0]);
if(nbytes != 0) _exit(2);
}
return 0;
}
Here is the code, where parent process writes a string input in pipe and children processes read this from pipe. If child process reads from pipe the word "end", then i want to terminate all the processes and then terminate itself, and if reads the word "finish" i want to raise a signal to father for killing all the processes and then exit. I run the code and i had segmentation fault. Why it is wrong?
#define _POSIX_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
void measure_time(int sig)
{
printf("child [%d] received signal %d\n", getpid(), sig);
}
int main(int argc, char *argv[])
{
int n_task = 4;
pid_t pid;
pid_t pid_array[n_task];
int fd[2];
for (int i = 0; i < n_task; i++)
{
pid = fork();
if (pipe(fd) == -1)
{
perror(" pipe ");
exit(1);
}
if (pid < 0)
{
perror("fork");
exit(1);
}
if (pid == 0) //child
{
char *buf;
close(fd[1]);
read(fd[0], buf, 10);
printf("I read: %s", buf);
if (strcmp(buf, "end") == 0)
{
for (int i = 0; i < n_task; i++)
kill(pid_array[i], SIGUSR1);
}else if(strcmp(buf,"finish") == 0){
/*Here i want father to kill all children and then exit.*/
}
exit(0);
}
close(fd[0]);
char *buf;
printf("Give the input string: \n");
scanf("%s", buf);
write(fd[1], buf, strlen(buf));
close(fd[1]);
pid_array[i] = pid;
}
sleep(1);
for (int i = 0; i < n_task; i++)
wait(NULL);
return (0);
}
Besides the issue of uninitialized buf identified by #G. Sliepen, the pipe() need be called before fork() as file descriptors are kept open when forking child process(s). This is also how pipe works.
You can try to change your code snippet to put pipe() before fork().
...
if (pipe(fd) == -1)
{
perror(" pipe ");
exit(1);
}
pid = fork();
if (pid < 0)
{
perror("fork");
exit(1);
}
...
Please read the manual page of pipe(2) in which an example presented.
SO has this post fork() and pipes() in c explained this as well.
Update for terminating process(s)
This child process has no knowledge about existence of its siblings, but its parent process has. If not explicitly required, you can let the parent to do so, i.e. to "end" all child processes.
BTW, instead of sending signal SIGUSR1 it is better to send SIGTERM signal. Although SIGUSSR1 can cause the target process be terminated by default (see signal(7)).
To "finish", i.e. to kill (or terminate) all the child processes as well as parent process, you can simplly kill the parent. All its descendants got killed as well. Or, you can send signal to the same process group. See kill(2).
You are declaring a pointer buf, but did not initialize it. Subsequent calls to read() and scanf() will fail because the pointer is invalid.
You need to make sure buf is initialized and pointing to valid memory. A simple way to fix your code is to do:
char buf[10];
read(fd[0], buf, 10);
If you enable compiler warnings with -Wall, then the compiler will warn you about initialized variables.
Be aware of potential buffer overflows: if you declare char buf[10], make sure you will never write more than ten bytes into it. Also, check the return value of functions like read(), write(), scanf() to ensure no errors were encountered, otherwise the contents of the buffers or output files might not be as expected.
I wrote a simple script (taken from a tutorial) which writes data to one end of a pipe in a child process, and reads it from the other end of the pipe in the parent process:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int mypipefd[2];
int ret;
char buf[20];
ret = pipe(mypipefd);
if (ret == -1) {
printf("Pipe failed.\n");
exit(1);
}
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!";
write(mypipefd[1], msg, strlen(msg) + 1);
} else {
printf("Parent process.\n");
read(mypipefd[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This works fine and outputs the results I expect:
Parent process.
Child process.
Buf: Hello there!
[ project ] $
Then as I got more familiar with the code, I wondered why we need to use mypipefd[2] and pipe() to achieve this goal, or whether mypipefd[1] by itself would work. So I tried it out with the following code:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
int main()
{
pid_t pid;
int my_array[1];
char buf[20];
if ((pid = fork()) == -1) {
printf("Fork failed.\n");
exit(1);
} else if (pid == 0) {
printf("Child process.\n");
char msg[] = "Hello there!\n";
write(my_array[0], msg, strlen(msg) + 1);
} else {
// wait(NULL);
printf("Parent process.\n");
read(my_array[0], buf, 15);
printf("Buf: %s\n", buf);
}
return 0;
}
This code outputs the same text, but it hangs after it finishes printing.
Parent process.
Child process.
Buf: Hello there!
No prompt, this time. I even tried un-commenting that call to wait(NULL), on the off-chance that the root cause was a conflict between parent and child processes. No such luck.
What's going on here? Why am I unable to read and write to a length-of-one array in this way without the program hanging? What exactly is the compiler stuck on?
A pipe, on computers as well as in real life, have two ends. And like pipes in real life, data flows from one end of the pipe (the write end) to the other (the read end).
The pipe function gives you those two ends by writing them to an array of two file-descriptors. The first element of the pair is read-only, and the second is write-only.
The pipe() function accepts an array of 2 integer as an input argument.
#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
It then generates a new pipe object, and initializes the pipefd array with file descriptors for read and write operation.
What you try to do is call read() and write() using some arbitrary, uninitialized ints (or file descriptor). Meaning the OS did not allocate a pipe object and did not provide you with file descriptors (the pipe's API) to be use with read() and write().
This (calling read() or write() with uninitialized file descriptor) will result in "undefined behavior".
"I find that a good working definition of "undefined behaviur" is "works for me, works for you, works during development and QA, but blows up in your most important customer's face"" --- Scott Meyers
My little program includes two pipes to create a multidirectional communication between father and son.
The write on s2f [1] returns -1 but I did not understand why.
Can you help me? Is there anything else that does not work or that I could improve?
/*
Write a program in C language that in sequence:
1) create 2 pipes and a child (the 2 pipes will be used for two-way communication between the parent
and son);
2) the father, after the creation of the child, takes in input from the user a file name;
3) send the child the name of the file using the first pipe;
4) make the child look for the number of spaces in the file and communicate this number to the father through the use of the second pipe;
5) let the father print the number received from son;
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/wait.h>
int main (int argc, char *argv[])
{
int f2s[2];
int s2f[2];
int fd, n;
pid_t p;
char buf[20];
char c;
int countspace=0, valueofspace;
if (argc<2)
{
printf("ERROR!\n");
exit (-1);
}
if (pipe (f2s) == -1 && pipe (s2f) == -1)
exit(-1);
p=fork();
if (p>0)
{
printf("I'm inside the father process.\n");
close(f2s[0]);
close(s2f[1]);
write(f2s[1],argv[1],sizeof(argv[1]));
read(s2f[0],&valueofspace, sizeof(int));
printf("The spaces are %d", valueofspace);
printf("Father exit\n");
exit(0);
}
if (p==0)
{
printf("I'm inside the child process.\n");
close(f2s[1]);
close(s2f[0]);
read (f2s[0],buf,20);
if (fd = open(buf, O_RDONLY) == -1)
printf("Error when opening the file\n");
while (read(fd,&c,1) > 0)
{
if (c==' ')
countspace++;
}
close(fd);
printf("Count: %d\n",countspace);
n = write(s2f[1],&countspace, sizeof(countspace));
printf("WRITE of %d BYTES\n", n);
printf("Son exit \n");
exit(0);
}
}
You have closed the reading end of the pipe s2f before writing into it.
close(s2f[0]);
So there will be a EPIPE error when you write into the pipe. From the online reference on write (with added emphasis):
The EPIPE error occurs when fd is connected to a pipe or socket whose reading end is closed. When this happens the writing process will also receive a SIGPIPE signal. (Thus, the write return value is seen only if the program catches, blocks or ignores this signal.)
Since your program does not catch, block or ignore this signal, the write return value is not as expected and instead is -1.
The following c program is used to send a message from parent process to the child process(created using fork()) via a pipe and is run on the linux terminal!
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc,char *arg[]){
pid_t child;
int pipefd[2];
int ret;
char message[20];
ret =pipe(pipefd);
if((child=fork())==0){
printf("The child process \n");
close(pipefd[0]);
write(pipefd[1],"Hello from parent",17);
}
else{
close(pipefd[1]);
read(pipefd[0],message,17);
printf("Message from parent %s\n",message);
}
return 0;
}
The above code prints the message "Hello from parent" but at the end of parent part an # sign is printed! what is the reason and how can i rectify it?
Send also null character that is at the end of the string. Same for reading.
write(pipefd[1],"Hello from parent",18);