I made this program with pipes to communicate two processes with PIPES. Now what I have to do is the same but with FIFO.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
#include <string.h>
int main()
{
int e, p[20], hijo1, hijo2, nbytes, readbytes;
char texto[200], readbuffer[100];
printf("Write the message to send to the other process\n");
fgets(texto, 100, stdin);
pipe(p);
if ((hijo1 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo1 == 0)
{
printf("Im %d and Im child 1\n", getpid());
close(p[0]);
write(p[1], texto, strlen(texto + 1));
close(p[1]);
exit(0);
}
if ((hijo2 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo2 == 0)
{
printf("Im %d And Im child 2 \n", getpid());
close(p[1]);
write(1, "message received: ", 24);
while ((nbytes = read(p[0], readbuffer, 8)) == 8)
{
write(1, readbuffer, nbytes);
}
write(1, readbuffer, nbytes);
printf("\n");
close(p[0]);
exit(0);
}
printf("Im %d and Im the father\n", getpid());
waitpid(hijo1, &e, 0);
waitpid(hijo2, &e, 0);
exit(EXIT_SUCCESS);
}
This is what I tried to do but with FIFO
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
#include <string.h>
int main()
{
char texto[200], buf[200];
int fd, fd2, hijo1, hijo2, nbytes;
printf("Ingrese el mensaje para enviar al FIFO\n");
fgets(texto, 100, stdin);
printf("soy %d y soy el padre \n", getpid());
mkfifo("/tmp/mi_fifo", 0666);
if ((hijo1 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo1 == 0)
{
printf("soy %d y soy el hijo 1 \n", getpid());
fd = open("/tmp/mi_fifo", O_WRONLY);
write(fd, texto, sizeof(texto + 1));
close(fd);
exit(0);
}
if ((hijo2 = fork()) == -1)
{
printf("ERROR FORK\n");
exit(EXIT_FAILURE);
}
if (hijo2 == 0)
{
printf("soy %d y soy el hijo 2 \n", getpid());
fd2 = open("/tmp/mi_fifo", O_RDONLY);
write(1, "el mensaje recibido es: \n", 24);
while (nbytes = read(fd2, buf, 8) == 8)
{
write(1, buf, nbytes);
}
write(1, buf, nbytes);
close(fd2);
exit(0);
}
return 0;
}
This Fifo program is not receiving the Message from the other child process. When I print the buf variable with Write() It shows only one letter. It should show the whole message that's why it is in a while loop. How can I do that? I haven't found any information about fork processes and FIfOs I hope you can help me.
At least two problems:
sizeof(texto + 1) needs to be strlen(texto)+1 to ensure the right size for the string in the buffer.
while (nbytes = read(fd2, buf, 8) == 8) needs to be while ((nbytes = read(fd2, buf, 8)) == 8). Because == has higher precedence than =. What you have assigns either 1 or 0 (boolean result) to nbytes.
Related
I am self-studying an OS textbook and doing its homework:
Write a program that creates two children, and connects the standard output of one to the standard input of the other, using the pipe() system call.
then I try to write my code like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
printf("parent in pid: (%d)\n", (int)getpid());
fflush(stdout);
int p1[2], p2[2];
pipe(p1);
pipe(p2);
char buff1[100];
char buff2[100];
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0)
{
int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd);
printf("entering child1 process at pid : (%d)\n", (int)getpid());
dup2(p1[0], STDIN_FILENO);
dup2(p2[1], STDOUT_FILENO);
int n = read(STDIN_FILENO, buff1, sizeof buff1);
puts("this is a message from child 1");
write(fd, buff1, n);
}
else
{
int rc2 = fork();
if (rc2 == 0)
{
int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd2);
printf("entering child2 process at pid : (%d)\n", (int)getpid());
dup2(p2[0], STDIN_FILENO);
dup2(p1[1], STDOUT_FILENO);
int n = read(STDIN_FILENO, buff2, sizeof buff2);
puts("this is a message from child 2");
write(fd2, buff2, n);
}
else
{
printf("final parent in pid: (%d)\n", (int)getpid());
}
}
return 0;
}
if all went correctly. I should see messages from child1 or child2 in the txt files. But nothing happened when I run this code.
But if I delete any one of the read statement like this:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
printf("parent in pid: (%d)\n", (int)getpid());
fflush(stdout);
int p1[2], p2[2];
pipe(p1);
pipe(p2);
char buff1[100];
char buff2[100];
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0)
{
int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd);
printf("entering child1 process at pid : (%d)\n", (int)getpid());
dup2(p1[0], STDIN_FILENO);
dup2(p2[1], STDOUT_FILENO);
//int n = read(STDIN_FILENO, buff1, sizeof buff1);
puts("this is a message from child 1");
//write(fd, buff1, n);
}
else
{
int rc2 = fork();
if (rc2 == 0)
{
int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd2);
printf("entering child2 process at pid : (%d)\n", (int)getpid());
dup2(p2[0], STDIN_FILENO);
dup2(p1[1], STDOUT_FILENO);
int n = read(STDIN_FILENO, buff2, sizeof buff2);
puts("this is a message from child 2");
write(fd2, buff2, n);
}
else
{
printf("final parent in pid: (%d)\n", (int)getpid());
}
}
return 0;
}
or like this
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
printf("parent in pid: (%d)\n", (int)getpid());
fflush(stdout);
int p1[2], p2[2];
pipe(p1);
pipe(p2);
char buff1[100];
char buff2[100];
int rc = fork();
if (rc < 0)
{
fprintf(stderr, "fork failed");
exit(1);
}
else if (rc == 0)
{
int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd);
printf("entering child1 process at pid : (%d)\n", (int)getpid());
dup2(p1[0], STDIN_FILENO);
dup2(p2[1], STDOUT_FILENO);
int n = read(STDIN_FILENO, buff1, sizeof buff1);
puts("this is a message from child 1");
write(fd, buff1, n);
}
else
{
int rc2 = fork();
if (rc2 == 0)
{
int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd2);
printf("entering child2 process at pid : (%d)\n", (int)getpid());
dup2(p2[0], STDIN_FILENO);
dup2(p1[1], STDOUT_FILENO);
//int n = read(STDIN_FILENO, buff2, sizeof buff2);
puts("this is a message from child 2");
//write(fd2, buff2, n);
}
else
{
printf("final parent in pid: (%d)\n", (int)getpid());
}
}
return 0;
}
I could see correct output in the txt file from both sides.
I'm wondering what happened in my code and what went wrong in the first case?
A few issues in the code:
Both of your child processes block on reading from the pipes, but nothing ever gets written into those, so they block forever. A fix is to write into the pipes before reading.
fflush is required to make sure stdout buffer is written into STDOUT_FILENO. stdout is line-buffered when connected to a terminal, and block-buffered otherwise (the determination is made before main is invoked), so that puts behaves differently when stdout is not connected to a terminal at program start-up.
The parent process should wait for children to terminate. If/when the parent process is a session leader and it terminates, the kernel sends SIGHUP to all (child) processes in its group. More details.
Code with fixes:
int main() {
printf("parent in pid: (%d)\n", (int)getpid());
fflush(stdout);
int p1[2], p2[2];
pipe(p1);
pipe(p2);
char buff1[100];
char buff2[100];
int rc = fork();
if (rc == 0)
{
int fd = open("test1.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd);
printf("entering child1 process at pid : (%d)\n", (int)getpid());
fflush(stdout);
dup2(p1[0], STDIN_FILENO);
dup2(p2[1], STDOUT_FILENO);
puts("this is a message from child 1");
fflush(stdout);
int n = read(STDIN_FILENO, buff1, sizeof buff1);
write(fd, buff1, n);
}
else
{
int rc2 = fork();
if (rc2 == 0)
{
int fd2 = open("test2.txt", O_CREAT|O_WRONLY|O_TRUNC, S_IRWXU);
printf("%d\n", fd2);
printf("entering child2 process at pid : (%d)\n", (int)getpid());
fflush(stdout);
dup2(p2[0], STDIN_FILENO);
dup2(p1[1], STDOUT_FILENO);
puts("this is a message from child 2");
fflush(stdout);
int n = read(STDIN_FILENO, buff2, sizeof buff2);
write(fd2, buff2, n);
}
else
{
printf("final parent in pid: (%d)\n", (int)getpid());
waitpid(rc, &rc, 0);
waitpid(rc2, &rc2, 0);
}
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main() {
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a, child_b;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p1[0]);
close(p1[1]);
}
} else {
child_b = fork();
if (child_b == 0) {
while (1) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p2[0]);
close(p2[1]);
}
} else {
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s", &choice, msgbuf);
switch (choice) {
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
default:
printf("Process does not exist");
break;
case -1:
close(p1[0]);
close(p2[0]);
printf("parent waiting");
wait(NULL);
exit(0);
}
}
}
}
return 0;
}
In the above program I have a parent making two child processes belonging to that same parent. The user writes to the parent process which pipes the message to be read by either child 1 or child 2. It keeps doing this continuously unless the user inputs -1.
The problem is that case in my switch statement doesn't get executed and instead the program hangs. I think I have my pipes closed at the correct places.
You need to send some signal to your child process to inform then to terminate before waiting for them to exit. You should define some pre-defined message which means its time for child to terminate. Check below code. Here pre-defined message is "-1". You should choose your own which doesn't conflict with your application's real data.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#define MSGSIZE 64
char msgbuf[MSGSIZE];
int main() {
int p1[2];
int p2[2];
int nread;
int choice = 0;
pid_t child_a, child_b;
if (pipe(p1) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
if (pipe(p2) == -1) {
printf("error in creating pipe\n");
exit(-1);
}
child_a = fork();
if (child_a == 0) {
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p1[0]);
close(p1[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
child_b = fork();
if (child_b == 0) {
while (1) {
dup2(p2[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
printf("%d receives message: %s\n", getpid(), msgbuf);
close(p2[0]);
close(p2[1]);
if (strcmp(msgbuf, "-1") == 0) { // check if time to end
break;
}
}
} else {
while (1) {
printf("<child_to_receive_msg> <message>\n");
scanf("%d %s", &choice, msgbuf);
switch (choice) {
case 1:
usleep(250);
write(p1[1], msgbuf, MSGSIZE);
break;
case 2:
usleep(250);
write(p2[1], msgbuf, MSGSIZE);
break;
default:
printf("Process does not exist\n");
break;
case -1:
strcpy(msgbuf, "-1");
write(p1[1], msgbuf, MSGSIZE); // send message to end
close(p1[0]);
close(p2[0]);
printf("parent waiting\n");
wait(NULL);
exit(0);
}
}
}
}
return 0;
}
First, you need to start performing error checking. Check the man page of the calls you make. Add checks in your code to detect errors. When they return an error, use perror and exit(EXIT_FAILURE);.
Second, you need to start paying attention to the values returned by read and write since they could be less than expected. These need to be called in a loop.
For example, for read, you'd use the following:
#include <errno.h>
#include <limits.h>
// Returns the number of bytes read.
// EOF was reached if the number of bytes read is less than requested.
// On error, returns -1 and sets errno.
ssize_t read_fixed_amount(int fd, char *buf, size_t size) {
if (size > SSIZE_MAX) {
errno = EINVAL;
return -1;
}
ssize_t bytes_read = 0;
while (size > 0) {
ssize_t rv = read(fd, buf, size);
if (rv < 0)
return -1;
if (rv == 0)
return bytes_read;
size -= rv;
bytes_read += rv;
buf += rv;
}
return bytes_read;
}
It would be used something like this:
ssize_t bytes_read = read_fixed_amount(fd, buf, size);
if (bytes_read < 0) {
perror("read");
exit(EXIT_FAILURE);
}
if (bytes_read == 0) {
printf("EOF reached\n");
exit(EXIT_SUCCESS);
}
if (bytes_read != size) {
fprintf(stderr, "read: Premature EOF.\n");
exit(EXIT_FAILURE);
}
Third, reading from the pipe will only return EOF once all file descriptors of the write end of the pipes have been closed.
Right after the fork, the parent should do
close(p1[0]);
close(p2[0]);
Right after the fork, child 1 should do
close(p1[1]);
close(p2[0]);
close(p2[1]);
Right after the fork, child 2 should do
close(p1[0]);
close(p1[1]);
close(p2[1]);
Fourth, there's this monstrosity:
while (1) {
dup2(p1[0], STDIN_FILENO);
read(STDIN_FILENO, msgbuf, MSGSIZE);
...
close(p1[0]);
close(p1[1]);
}
Really? Infinite loop. Attempt to repeatedly make STDIN a dup of p1[0]. Duping of a closed descriptor.
This should appear before the loop:
dup2(p1[0], STDIN_FILENO);
close(p1[0]);
Or you could skip those two call and simply read from p1[0] instead of STDIN_FILENO.
As for the infinite loop, it goes back to the second point. Check the value returned by read.
Fifth, you only wait for one child to finish, but there are two children to wait for. You need to call wait twice.
I have the following code with output:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#define PIPE_STDIN 0
#define PIPE_STDOUT 1
#define msg "hello world"
int main()
{
int fd_pipe[2];
int ret = fork();
if (ret < 0)
{
printf("Failed to fork\n");
return -1;
}
else if (ret == 0)
{
printf("Parent with PID %d\n", getpid()); fflush(stdout);
//sleep(3);
ret = write(fd_pipe[PIPE_STDOUT], msg, sizeof(msg)); fflush(stdout);
printf("Parent wrote string %d\n", ret); fflush(stdout);
wait( NULL );
printf("Parent done wait\n"); fflush(stdout);
}
else
{
char buf[80];
printf("Child with PID %d whose parent PID %d\n", getpid(), ret); fflush(stdout);
ret = read(fd_pipe[PIPE_STDIN], buf, sizeof(msg));
printf("Child read %s %d\n", buf, ret); fflush(stdout);
}
}
Output:
Child with PID 1130 whose parent PID 1131
Child read -1
Parent with PID 1131
hello world Parent wrote string 12
Parent done wait
From the output, why would child failed to read from pipe (returned -1) and then later on message "hello world" was printed ? Please explain the execution order that gives the above log.
You should call pipe before fork to init file descriptor.
fork() == 0 means child process.
The follow code could work:
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <wait.h>
#define PIPE_STDIN 0
#define PIPE_STDOUT 1
#define msg "hello world"
int main()
{
int fd_pipe[2];
int ret;
if (pipe(fd_pipe) == -1) {
perror("pipe");
return -1;
}
ret = fork();
if (ret < 0)
{
printf("Failed to fork\n");
return -1;
}
else if (ret != 0)
{
printf("Parent with PID %d\n", getpid()); fflush(stdout);
//sleep(3);
ret = write(fd_pipe[PIPE_STDOUT], msg, sizeof(msg)); fflush(stdout);
printf("Parent wrote string %d\n", ret); fflush(stdout);
wait( NULL );
printf("Parent done wait\n"); fflush(stdout);
}
else
{
char buf[80];
printf("Child with PID %d whose parent PID %d\n", getpid(), getppid()); fflush(stdout);
ret = read(fd_pipe[PIPE_STDIN], buf, sizeof(msg));
printf("Child read %s %d\n", buf, ret); fflush(stdout);
}
}
I'm trying to code a simple fork() and pipe() program which gets input from the user and outputs it through the pipe in the childprocess. But somehow I'm not getting the result I wished to get.
The first input works fine, for example I type in "Hi" and get the result "Prozessmanager: Hi", but as soon as I try to input the next string, it crashes or somehow stops working until I input a "Q" which exits my Program.
I tried to debug it and got the result, that I'm trying to write into a broken pipe.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
//#include <signal.h>
#define BUFSIZE 512
//int clock = 0;
//void handler(int signum) {
//clock++;
//printf("Clock: 00:00:%d\n", clock);
//}
int main(int argc, char** argv) {
pid_t prozessmanager;
pid_t reporter;
int pipefd[2];
int status;
char str[BUFSIZE];
char buf[BUFSIZE];
if ((pipe(pipefd)) == -1) {
perror("pipe() error");
exit(1);
}
if ((prozessmanager = fork()) == -1) {
perror("fork() error");
exit(1);
} else if (prozessmanager == 0) { //Prozessmanager prozess
while (1) {
//signal(SIGALRM, handler);
//while(1){
//alarm(1);
//}
close(pipefd[1]);
read(pipefd[0], buf, sizeof (buf));
/*if (*buf == 'S') {
//handler(clock);
} else {*/
if (*buf == 'P') {
if ((reporter = fork()) == -1) {
perror("fork() error");
exit(1);
} else if (reporter == 0) { //Reporter prozess
printf("Im a Report Prozess, PID: %d\n", getpid());
exit(0);
} else { //Prozessmanager waits for Reporter
wait(&status);
printf("Report terminated, PID: %d\n", reporter);
break;
}
} else if (*buf == 'Q') {
printf("Exit Prozessmanager, PID: %d\n", getpid());
exit(0);
} else {
printf("Prozessmanager: %s", buf);
break;
}
//}
}
} else { //Kommandant prozess
while (1) {
close(pipefd[0]);
fgets(str, 80, stdin);
write(pipefd[1], str, sizeof (str));
if (*str == 'Q') {
break;
}
}
wait(&status);
printf("Exit Kommandant, PID: %d\n", getpid());
exit(0);
}
return (0);
}
So I need this program which needs to create argv[1] child using fork() and print what children number are they and what PID do they have in order of its creation.
I have to do that using pipes blocking properties.
Example output:
I am child 1 and my PID is 25853.
I am child 2 and my PID is 25854.
I am child 3 and my PID is 25855.
This is what I have tried so far, but it doesn't respect the order of children creation.
int main(int argc, char* argv[])
{
char buffer[80];
int p[2], i;
int pid = getpid();
for (i = 0; i < atoi(argv[1]); i++) {
pipe(p);
if (fork() == 0) {
read(p[0], &pid, sizeof(pid)); // It should block here until there's
// something in the pipe to read
sprintf(buffer, "I am child %d and my PID is %d\n", i + 1, getpid());
write(1, &buffer, strlen(buffer));
close(p[0]);
close(p[1]);
exit(0);
}
else { // parent
close(p[0]);
write(p[1], &pid, sizeof(pid));
close(p[1]); // The child is able to read the EOF now.
}
}
while ((waitpid(-1, NULL, 0)) > 0)
;
close(p[0]);
close(p[1]);
sprintf(buffer, "I've finished\n");
write(1, &buffer, strlen(buffer));
}
I feel like I am close but I am not using the pipes block poperties correctly.
I need some advice, thanks.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char* argv[])
{
if (argc != 2) {
return 1;
}
int const n = atoi(argv[1]);
for (int i = 0; i < n; i++) {
int p[2];
if (pipe(p) != 0)
return 1;
int pid = fork();
if (pid == 0) {
close(p[1]);
if (read(p[0], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[0]);
fprintf(stdout, "I am child %d and my PID is %d\n", i + 1, pid);
return 0;
}
else if (pid > 0) {
close(p[0]);
if (write(p[1], &pid, sizeof pid) != sizeof pid)
return 1;
close(p[1]);
if (waitpid(pid, NULL, 0) == -1)
return 1;
}
else {
return 1;
}
}
fprintf(stdout, "I've finished\n");
}