how to use pipe to connect two child process in C - c

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;
}

Related

Passing data from one pipe to another

I am new to pipes but how do I redirect the output from child_1 to the input for child_2?
I am trying to pass the value from the parent to child_1, adds 1 to the value, print the value, then use that output and pass it into child_2, add 1 again, and finally print the value.
The code below has the right output value for child_1, but not for child_2, how do I redirect the output from child_1 to the input for child_2?
Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char * argv[]) {
int fd[2];
int PID;
pipe(fd); //fd1[0] = read | fd1[1] = write
PID = fork(); // spawn child_1
if (PID < 0){ // failed to fork
perror("Unable to fork child");
exit(1);
}
if (PID > 0) { // parent
int value = 100;
// since parent is only writing, close the reading end of pipe
close(fd[0]);
// write the data to the write end of the pipe
write(fd[1], &value, sizeof(int));
// then close the writing end of the pipe (parent)
close(fd[1]);
/**********************************************************/
} else { // child 1
int val = 0;
// read from the parent pipe
read(fd[0], &val, sizeof(int));
val += 1;
// is this how to redirect from one pipe to another?
dup2(fd[0], fd[1]);
// this prints the right value for val (val [101] = value [100] + 1)
printf("Child [%d] read value %d\n", getpid(), val);
// close the reading end of the pipe for child_1
close(fd[0]);
int PID2 = fork(); // make child 2
if(PID2 == 0) { // child 2
int val2 = 0;
close(0); // close stdin since we are trying to take the value from child_1
// read input from child_1 pipe (NOT WORKING?)
read(fd[0], &val2, sizeof(int));
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
}
}
return EXIT_SUCCESS;
}
The way you have things set up, there's no need to use dup2() or any other I/O redirection.
Add #include <unistd.h> to the list of include files (and remove #include <string.h> — it seems to be unused)
Delete: dup2(fd[0], fd[1]);
Delete: close(fd[0]);
Delete: close(0);
Before the second fork(), add write(fd[1], &val, sizeof(val));
When you have close(fd[0]) in the first child, you effectively close fd[0] for the second child too.
You should check the status of the read and write operations before using the results.
Those changes lead to:
/* SO 7383-1815 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
int fd[2];
int PID;
pipe(fd);
PID = fork();
if (PID < 0)
{
perror("Unable to fork child");
exit(EXIT_FAILURE);
}
if (PID > 0)
{
int value = 100;
close(fd[0]);
write(fd[1], &value, sizeof(int));
close(fd[1]);
}
else
{
int val = 0;
if (read(fd[0], &val, sizeof(val)) != sizeof(val))
{
perror("read() failed in child 1");
exit(EXIT_FAILURE);
}
val += 1;
printf("Child [%d] read value %d\n", getpid(), val);
if (write(fd[1], &val, sizeof(val)) != sizeof(val))
{
perror("write() failed in child 1");
exit(EXIT_FAILURE);
}
int PID2 = fork();
if (PID2 == 0)
{
int val2 = 0;
if (read(fd[0], &val2, sizeof(val2)) != sizeof(val2))
{
perror("read() failed in child 2");
exit(EXIT_FAILURE);
}
val2 += 1;
printf("Child [%d] out %d\n", getpid(), val2);
close(fd[0]);
close(fd[1]);
}
}
return EXIT_SUCCESS;
}
When compiled (cleanly with options set fussy), it produces output such as:
Child [34520] read value 101
Child [34521] out 102
I believe this is what was wanted.

Using sed with the execvp to cut part of stout. C

I'm using a function that echo a string and redirect output to a sed input in c.
If i echo a string like "hello: bye bye", i need to cut everything before the ":". So i buildt a function that fork and pipe for this but sed won't recognize my regex:
void sender (char * str_ ,char * pipe_ ,char **args_) {
int fd[2];
int pid;
char* cmd1[] = {"echo", str_,NULL};
char* sed[] = {"sed","'[^:]*$'",NULL};
int status;
pid = fork();
if (pid == 0) {
if(pipe(fd) < 0){
exit(100);
}
pid = fork();
if (pid == 0) {
close(fd[0]);
dup2(fd[1], 1);
close(fd[1]);
execvp(cmd1[0], cmd1);
printf("Error in execvp1\n");
}else{
close(fd[1]);
wait(&status);
dup2(fd[0],0);
close(fd[0]);
dup2(1,2);
execvp(sed[0],sed);
printf("Error in execvp2\n");
}
}
else{
close(fd[0]);
close(fd[1]);
wait(&status);
wait(&status);
}
}
The output is error for every line read because of sed:expression -e #1, character 1: unknown command: `''
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
void pipe_exec(int pfd[], char *cmd_args[], int redirect_output)
{
printf("%s, pid %d\n", cmd_args[0], getpid());
if (redirect_output)
dup2(pfd[1], 1);
else
dup2(pfd[0], 0);
close(pfd[0]);
close(pfd[1]);
execvp(cmd_args[0], cmd_args);
printf("Error in execvp\n");
exit(1);
}
void sender(char *str_, char *unused1, char **unused2)
{
int status, pid, fd[2];
char *cmd1[] = { "echo", str_, NULL };
char *sed[] = { "sed", "s/[^:]*://", NULL };
if (pipe(fd) < 0)
exit(100);
pid = fork();
if (pid == 0)
pipe_exec(fd, cmd1, 1);
pid = fork();
if (pid == 0)
pipe_exec(fd, sed, 0);
close(fd[0]);
close(fd[1]);
wait(&status);
wait(&status);
}
int
main(void)
{
sender("hello: bye bye", NULL, NULL);
return (0);
}

Child process read from pipe failed and seemed to be out of order

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);
}
}

C fork and pipe printing pid in order

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");
}

Pipes between child processes

I wrote a C program that is supposed to create a certain number of child processes, each child process having to change 1 letter from a string. The string and the number of child processes are read from the keyboard.
I want to do it using pipes. It should work like this: The parent changes one letter, then the first child takes the string modified by the parent and changes one more letter. The second child takes the string modified by the first one (2 letters are already changed) and changes one more and so on. I am new to C and am not quite sure how it all works, especially pipes.
Also can the children be linked between them through the pipe, or can they only be linked to the parent and it has to be something like: first child changes a letter, gives the string back to the parent and then the second child reads from there, modifies letter and gives back.
If it's like that, is there any way to make sure that this doesn't happen: Apples becomes AppleD and then AppleX and then AppleQ?
For example:
input:
3 Apples
output:
Applex Appldx Apqldx
My problem is: I don't get any output from the children. Unsure what I'm doing wrong. Help would be much appreciated, thanks in advance!
Here's my code:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<sys/wait.h>
void error(char* msg)
{
fprintf(stderr, "%s\n", msg);
exit(1);
}
char* modify(char msg[])
{
srand(time(NULL));
int pos1=rand()%((int)strlen(msg));
srand(time(NULL));
int pos2=rand()%26;
srand(time(NULL));
int big=rand()%2;
if(big==1)
{
msg[pos1]=(char)(((int)'A')+pos2);
}
else
{
msg[pos1]=(char)(((int)'a')+pos2);
}
return msg;
}
int main(int argc, char *argv[])
{
if(argc!=3)
{
error("Wrong number of arguments\n");
}
int nrch;
nrch=atoi(argv[1]);
char* msg=argv[2];
printf("Parent: erhalten: %s\n", msg);
int i=0;
msg=modify(argv[2]);
printf("Parent: weiter: %s\n", msg);
pid_t pids[10];
int fd[2];
if(pipe(fd) == -1)
{
error("Can't create the pipe");
}
dup2(fd[1], 1);
close(fd[0]);
fprintf(stdout, msg);
/* Start children. */
for (i = 0; i < nrch; ++i)
{
if ((pids[i] = fork()) < 0)
{
error("Can't fork process");
}
else if (pids[i] == 0)
{
dup2(fd[0], 0);
close(fd[1]);
fgets(msg,255,stdin);
printf("child%d: erhalten: %s\n", (i+1), msg);
modify(msg);
printf("child%d: weiter: %s\n", (i+1), msg);
if (pipe(fd) == -1)
{
error("Can’t create the pipe");
}
fprintf(stdout, msg);
dup2(fd[1], 1);
close(fd[0]);
exit(0);
}
}
/* Wait for children to exit. */
int status;
pid_t pid;
while (nrch > 0)
{
pid = wait(&status);
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
--nrch;
}
}
One reason you see no output from the children is that you hook their standard output to the write end of the pipe, so when they write to standard output, it goes into the pipe, not to the screen (or wherever you sent the standard output of the program to originally).
Where the children are not going to execute a program that needs standard input and standard output going to the pipe, don't use I/O redirection. Just write to and read from the correct ends of the pipe.
If you've got multiple children, you probably need a pipe per child, but the parent process will need to do the creating. Your code creates a pipe in the child; that pipe is no use because only the child knows about it. You probably can do it all with one pipe, but it becomes indeterminate which sequence the children will run in. If determinacy is important, use multiple pipe() calls, and at least twice as many close() calls.
Single pipe solution
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
static void error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
putc('\n', stderr);
exit(1);
}
static void modify(char msg[])
{
int pos1 = rand() % ((int)strlen(msg));
int pos2 = rand() % 26;
int big = rand() % 2;
if (big == 1)
msg[pos1] = (char)(((int)'A') + pos2);
else
msg[pos1] = (char)(((int)'a') + pos2);
}
static int read_pipe(int fd, char *buffer, size_t buflen)
{
int nbytes = read(fd, buffer, buflen);
if (nbytes <= 0)
error("Unexpected EOF or error reading pipe");
assert((size_t)nbytes < buflen);
buffer[nbytes] = '\0';
return nbytes;
}
int main(int argc, char *argv[])
{
if (argc != 3)
error("Usage: %s number 'message'", argv[0]);
srand(time(NULL));
int nrch = atoi(argv[1]);
char *msg = argv[2];
size_t len = strlen(msg);
printf("Parent: erhalten: %s\n", msg);
modify(msg);
printf("Parent: weiter: %s\n", msg);
int fd[2];
if (pipe(fd) == -1)
error("Can't create the pipe");
if (write(fd[1], msg, len) != (ssize_t)len)
error("Failed to write to pipe");
/* Start children. */
for (int i = 0; i < nrch; ++i)
{
int pid;
if ((pid = fork()) < 0)
error("Can't fork process");
else if (pid == 0)
{
char buffer[255];
int nbytes = read_pipe(fd[0], buffer, sizeof(buffer));
printf("child%d: erhalten (%d): %s\n", (i + 1), nbytes, buffer);
modify(buffer);
printf("child%d: weiter (%d): %s\n", (i + 1), nbytes, buffer);
write(fd[1], buffer, nbytes);
exit(0);
}
else
printf("Random: %d\n", rand());
}
/* Wait for children to exit. */
while (nrch > 0)
{
int status;
pid_t pid = wait(&status);
printf("Child with PID %ld exited with status 0x%.4X.\n", (long)pid, status);
--nrch;
}
char buffer[255];
int nbytes = read_pipe(fd[0], buffer, sizeof(buffer));
printf("Parent: weiter (%d): %s\n", nbytes, buffer);
return 0;
}
Example output
Code in file p1.c:
$ make p1 && ./p1 4 "Absolutely nothing to do with me"
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror p1.c -o p1
Parent: erhalten: Absolutely nothing to do with me
Parent: weiter: AbsolutEly nothing to do with me
Random: 1120753102
child1: erhalten (32): AbsolutEly nothing to do with me
Random: 918317477
child1: weiter (32): AbsolutEly notzing to do with me
child2: erhalten (32): AbsolutEly notzing to do with me
child2: weiter (32): AbsolwtEly notzing to do with me
Random: 196864950
child3: erhalten (32): AbsolwtEly notzing to do with me
child3: weiter (32): AbsolwtEly notzing to ao with me
Random: 1584398270
Child with PID 42928 exited with status 0x0000.
Child with PID 42927 exited with status 0x0000.
Child with PID 42926 exited with status 0x0000.
child4: erhalten (32): AbsolwtEly notzing to ao with me
child4: weiter (32): AbsolwtEly notzing to ao with Ue
Child with PID 42929 exited with status 0x0000.
Parent: weiter (32): AbsolwtEly notzing to ao with Ue
$
Note the stray use of rand() in the loop. It makes sure the children change different letters in the message. Without that, they all end up changing the same 'random' letter in the same 'random' position in the message.
You can create a multi-pipe solution if you wish. I got what appeared to be deterministic behaviour from the single-pipe solution, though there is no guarantee of the sequencing. If, for example, each child waited for a random delay using nanosleep() or equivalent:
struct timespec nap = { .tv_sec = 0, .tv_nsec = (rand() % 1000) * 1000000 };
nanosleep(&nap, 0);
then you get an arbitrary sequence in the child processing. For example:
Parent: erhalten: Absolutely nothing to do with me
Parent: weiter: Absolutely nothinglto do with me
Random: 2028074573
Random: 988903227
Random: 1120592056
Random: 359101002
child4: erhalten (32): Absolutely nothinglto do with me
child4: weiter (32): vbsolutely nothinglto do with me
Child with PID 43008 exited with status 0x0000.
child3: erhalten (32): vbsolutely nothinglto do with me
child3: weiter (32): vbsolutelyGnothinglto do with me
Child with PID 43007 exited with status 0x0000.
child2: erhalten (32): vbsolutelyGnothinglto do with me
child2: weiter (32): vbsolutelyGnothinglto doawith me
Child with PID 43006 exited with status 0x0000.
child1: erhalten (32): vbsolutelyGnothinglto doawith me
child1: weiter (32): vbsolutelyGnothinglto doawimh me
Child with PID 43005 exited with status 0x0000.
Parent: weiter (32): vbsolutelyGnothinglto doawimh me
Tried to change your code acc to below, not sure if this is exectly what you want.
Anyhow the children are running...
int main(int argc, char *argv[])
{
if (argc != 3)
{
error("Wrong number of arguments\n");
}
int nrch;
nrch = atoi(argv[1]);
char *msg = argv[2];
printf("Parent: erhalten: %s\n", msg);
int i = 0;
msg = modify(argv[2]);
printf("Parent: weiter: %s\n", msg);
pid_t pids[10];
int fd[2];
/* Start children. */
for (i = 0; i < nrch; ++i)
{
if ((pids[i] = fork()) < 0)
{
error("Can't fork process");
}
if (pipe(fd) == -1)
{
error("Can't create the pipe");
}
// printf ( " pids[i] %d , i %d \n", pids[i] , i);
if (pids[i] == 0)
{
if (dup2(fd[0], 0) == -1)
{
error("Can't dup2 (A)");
}
close(fd[1]);
fgets(msg, 255, stdin);
printf("child%d: erhalten: %s\n", (i + 1), msg);
modify(msg);
printf("child%d: weiter: %s\n", (i + 1), msg);
fprintf(stdout, msg);
}
else
{
// printf("in else i= %d \n",i);
if (dup2(fd[1], 0) == -1)
{
error("Can't dup2 (B)");
}
close(fd[0])
exit(0);
}
}
/* Wait for children to exit. */
int status;
pid_t pid;
while (nrch > 0)
{
pid = wait(&status);
if (pid > -1)
printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
--nrch;
}
return 0;
}

Resources