Two messages in a ring of N process in C with pipes - c

I implement a Ring of N generation like this.
(process 0)--pipe4--(process 3)
| |
| |
pipe 1 pipe 3
| |
| |
(process 1)--pipe2--(process 2)
So, the Process 0 is the father of process 1, the process 1 the father of process 2 etc...
The process 0 send a random number to process 1 via pipe1, process 1 generate an other random number, and send max between these two numbers to process 2 via pipe 2 etc...
The proess 0 is reading on the pipe4, so he is blocked, waiting for the last message, then show the winner.
What i want to do, is that the process 0 send the winner to all the process now.
I try to re-read the pipe on each process to make them lock until the answer is propagated but a re read in the same process for the same pipe => no block.
So i try to create an other pipe between each process for the communication of the winner. So after i send the random number, i read on the pipeWinner, but this not block the process too!!
i'm really confuse, i don"t know how to do it.
Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
struct Node {
int node;
int val;
int pid;
};
int main(int argc, const char * argv[]) {
//Generation correspond to the number of generation the user want to create
int nbGeneration = atoi(argv[1]);
int indexGeneration=1;
//This value store the new random created on each generation
int newValue=0;
int pid=0;
//Array of pipe
int tube[nbGeneration][2];
int tubeAnswer[nbGeneration-1][2];
//Our seed for the rand
int seed=time(NULL);
srand(seed);
//The struct for the first process
//Value initialize here
struct Node processInitiale;
processInitiale.node=0;
processInitiale.val =rand();
processInitiale.pid =getpid();
//The struct for the childs process, this struct store the winner too
struct Node processWinner;
processWinner.node=0;
processWinner.val =0;
processWinner.pid =0;
//Pipe the nbGeneration pipe for the inital process reading
pipe(tube[nbGeneration]);
//Create N generation
for(indexGeneration = 1 ; indexGeneration < nbGeneration; ++indexGeneration )
{
pipe(tube[indexGeneration]);
pipe(tubeAnswer[indexGeneration]);
pid = fork();
if(pid==-1)
{
printf("%s\n", "Erreur lors de la création du processus");
}
if(pid!=0)
{
if(indexGeneration==1) // Initial process - Write first value to the first child
{
close(tube[indexGeneration][0]);
write(tube[indexGeneration][1],&processInitiale,sizeof(processInitiale));
close(tube[indexGeneration][1]);
//This read is "bloquant", we gonna wait for the last children
close(tube[nbGeneration][1]);
read(tube[nbGeneration][0],&processWinner,sizeof(processWinner));
close(tube[nbGeneration][0]);
//Show result
printf("%s%d%s%d%s%d\n", "Processus PID: ",processInitiale.pid, " node ", processInitiale.node ," value: ", processInitiale.val);
printf("%s%d%s%d%s%d%s%d\n","Node: ",processInitiale.node," Winner is: ",processWinner.val," NODE: ",processWinner.node," PID: ",processWinner.pid );
}
break;
}
else if(pid==0) //If it's the children, let's read the precedent pipe, then write into the next pipe for the next children
{
//Reading in the precedent pipe (The first one was writtend by the initial process - so this one is lock in the case children execute before first father)
close(tube[indexGeneration][1]);
read(tube[indexGeneration][0],&processWinner,sizeof(processWinner));
close(tube[indexGeneration][0]);
//Creation on the new random value to compare
newValue = rand();
printf("%s%ld%s%d%s%d\n", "Processus PID: ",(long)getpid(), " node ", indexGeneration ," value: ", newValue);
//Compare, if more bigger, change the struct
if(newValue>processWinner.val)
{
processWinner.node= indexGeneration;
processWinner.val = newValue;
processWinner.pid = getpid();
}
//Write data into the next pipe for the next children
//The last children gonna write for the inital process at least
close(tube[indexGeneration+1][0]);
write(tube[indexGeneration+1][1],&processWinner,sizeof(processWinner));
close(tube[indexGeneration+1][1]);
//Trying to read in the pipeAnswer but this one didn't block my process.
close(tubeAnswer[indexGeneration][0]);
read(tubeAnswer[indexGeneration][1],&processWinner,sizeof(processWinner));
close(tubeAnswer[indexGeneration][1]);
}
}
}

This is the code I ended up producing for this. I originally worked on it back in 2017, but recently another question appeared that had similar issues with a circle of pipes.
Source code: pipe97.c — compiled to executable pipe97.
/* SO 4626-6329 */
/*
** (process 0)--pipe0--(process 3)
** | |
** | |
** pipe1 pipe3
** | |
** | |
** (process 1)--pipe2--(process 2)
**
** So, the Process 0 is the parent of process 1; process 1 the
** parent of process 2; etc...
**
** Process 0 sends a random number to process 1 via pipe1; process 1
** generate an other random number, and send max between these two
** numbers to process 2 via pipe 2; etc...
**
** Process 0 is reading on pipe4, so it is blocked, waiting for
** the last message, then show the winner.
**
** What I want to do, is that the process 0 send the winner to all the
** process now.
**
** ********************************************************************
**
** Designate the 4 processes P0..P3.
** Designate the 4 pipes (channels) C0..C3.
**
** C0 must be created by P0 before creating P1.
** C1 must be created by P0 before creating P1.
** C2 must be created by P0 before creating P1 (because P1 needs to write to it).
** C3 must be created by P0 before creating P2 (because P2 needs to write to it).
** P0 will write to C1 and read from C0.
** P1 will read from C1 and write to C2.
** P2 will read from C2 and write to C3.
** P3 will read from C3 and write to C0.
**
** Hence Pn always reads from Cn and writes to C((n+1)%4).
** P0 writes then reads; the other processes read then write.
** Note that P1 and P2 should close C0 after forking the next child.
** PN (for N > 1) should close C1..C(N-1) too (it should be sufficient
** to close C(N-1) since P(N-1) closed the prior channels).
**
** Although the code does not rely on detecting EOF, the pipes will be
** closed, even though it is not crucial to the correct functioning of
** this program.
*/
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
struct Node
{
int node;
int val;
int pid;
};
static void no_children(void)
{
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
printf("PID %5d: child %5d exited 0x%.4X\n", (int)getpid(), corpse, status);
}
static void check_fds(void)
{
struct stat sb;
char buffer[128];
char *bufptr = buffer;
int n = snprintf(bufptr, sizeof(buffer), "PID %5d: ", (int)getpid());
bufptr += n;
for (int i = 0; i < 20; i++)
{
if (fstat(i, &sb) != 0)
*bufptr++ = '-';
else
*bufptr++ = 'o';
}
*bufptr++ = '\0';
printf("%s\n", buffer);
fflush(stdout);
}
static void pr_result(const char *tag, const struct Node *result)
{
char buffer[16];
snprintf(buffer, sizeof(buffer), "%.12s:", tag);
printf("%-13s PID = %5d, PPID = %5d, Node = %d (PID %5d), Value = %5d\n", buffer,
(int)getpid(), (int)getppid(), result->node, result->pid, result->val);
fflush(stdout);
}
static inline int new_bid(void)
{
return rand() % 10000;
}
static inline void pr_channel(int i, int c[2])
{
printf("%5d: C%d(%d,%d)\n", (int)getpid(), i, c[0], c[1]);
fflush(stdout);
}
static inline void mk_channel(int i, int c[2])
{
if (pipe(c) != 0)
{
fprintf(stderr, "%5d: failed to create pipe %d, (%d: %s)\n",
(int)getpid(), i, errno, strerror(errno));
exit(EXIT_FAILURE);
}
pr_channel(i, c);
}
static _Noreturn void be_parental(int i_pipe[2], int o_pipe[2])
{
int pid = getpid();
struct Node proc0 = { 0, new_bid(), pid };
struct Node winner = { 0, 0, 0 };
printf("PID %5d (PPID %5d): parent at work\n", pid, (int)getppid());
printf("FD {%d, %d, %d, %d}\n", i_pipe[0], i_pipe[1], o_pipe[0], o_pipe[1]);
check_fds();
pr_result("Opening bid", &proc0);
close(o_pipe[0]);
printf("Writing opening bid to fd %d\n", o_pipe[1]);
if (write(o_pipe[1], &proc0, sizeof(proc0)) != sizeof(proc0))
{
fprintf(stderr, "%5d: failed to write entry to fd %d (%d: %s)\n",
pid, o_pipe[1], errno, strerror(errno));
exit(EXIT_FAILURE);
}
close(i_pipe[1]);
if (read(i_pipe[0], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to read entry from fd %d (%d: %s)\n",
pid, i_pipe[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
//close(i_pipe[0]);
pr_result("Winning node", &winner);
if (write(o_pipe[1], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to write entry to fd %d (%d: %s)\n",
pid, o_pipe[1], errno, strerror(errno));
exit(EXIT_FAILURE);
}
close(o_pipe[1]);
/* Read final result once more */
if (read(i_pipe[0], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to read entry from fd %d (%d: %s)\n",
pid, i_pipe[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
close(i_pipe[0]);
pr_result("Recirculated", &winner);
no_children();
check_fds();
exit(EXIT_SUCCESS);
}
static _Noreturn void be_childish(int i, int i_pipe[2], int o_pipe[2])
{
struct Node winner;
int pid = getpid();
printf("PID %5d (PPID %5d) i = %d: child at work\n", pid, (int)getppid(), i);
printf("FD {%d, %d, %d, %d}\n", i_pipe[0], i_pipe[1], o_pipe[0], o_pipe[1]);
check_fds();
srand(pid);
close(i_pipe[1]);
if (read(i_pipe[0], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to read entry from fd %d (%d: %s)\n",
pid, i_pipe[0], errno, strerror(errno));
exit(EXIT_FAILURE);
}
pr_result("Incoming bid", &winner);
int newValue = new_bid();
printf("PID: %5d, new offer %5d\n", pid, newValue);
if (newValue > winner.val)
{
winner.node = i;
winner.val = newValue;
winner.pid = pid;
}
close(o_pipe[0]);
pr_result("Outgoing bid", &winner);
if (write(o_pipe[1], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to write entry to fd %d (%d: %s)\n",
pid, o_pipe[1], errno, strerror(errno));
exit(EXIT_FAILURE);
}
if (read(i_pipe[0], &winner, sizeof(winner)) != sizeof(winner))
exit(EXIT_FAILURE);
pr_result("Final winner", &winner);
close(i_pipe[0]);
/* Relay final result to next process */
if (write(o_pipe[1], &winner, sizeof(winner)) != sizeof(winner))
{
fprintf(stderr, "%5d: failed to write entry to fd %d (%d: %s)\n",
pid, o_pipe[1], errno, strerror(errno));
exit(EXIT_FAILURE);
}
close(o_pipe[1]);
/* There should be no children */
no_children();
check_fds();
exit(i);
}
int main(int argc, const char *argv[])
{
int numproc = 4;
if (argc > 1)
numproc = atoi(argv[1]);
if (numproc < 2 || numproc > 10)
{
fprintf(stderr, "Number of processes %d is out of the range 2..10\n", numproc);
exit(EXIT_FAILURE);
}
int seed = time(NULL);
printf("%5d: seed: %d\n", (int)getpid(), seed);
srand(seed);
int tube[numproc][2];
mk_channel(0, tube[0]);
mk_channel(1, tube[1]);
for (int i = 1; i < numproc; ++i)
{
if (i + 1 < numproc)
mk_channel(i + 1, tube[i + 1]);
int pid = fork();
if (pid == -1)
{
fprintf(stderr, "fork error for child %d (%d: %s)\n", i, errno, strerror(errno));
exit(1);
}
else if (pid == 0)
{
for (int c = 0; c < i; c++)
{
if ((i + 1) % numproc != c)
{
printf("%5d: closing %2d and %2d\n", (int)getpid(), tube[c][0], tube[c][1]);
close(tube[c][0]);
close(tube[c][1]);
}
}
be_childish(i, tube[i], tube[(i+1) % numproc]);
}
}
for (int c = 2; c < numproc; c++)
{
printf("%5d: closing %2d and %2d\n", (int)getpid(), tube[c][0], tube[c][1]);
close(tube[c][0]);
close(tube[c][1]);
}
be_parental(tube[0], tube[1]);
return 0;
}
Example run (6 processes requested):
$ pipe97 6
53200: seed: 1618329579
53200: C0(3,4)
53200: C1(5,6)
53200: C2(7,8)
53200: C3(9,10)
53201: closing 3 and 4
53200: C4(11,12)
PID 53201 (PPID 53200) i = 1: child at work
FD {5, 6, 7, 8}
PID 53201: ooo--oooo-----------
53202: closing 3 and 4
53200: C5(13,14)
53202: closing 5 and 6
PID 53202 (PPID 53200) i = 2: child at work
FD {7, 8, 9, 10}
PID 53202: ooo----oooo---------
53203: closing 3 and 4
53203: closing 5 and 6
53203: closing 7 and 8
PID 53203 (PPID 53200) i = 3: child at work
FD {9, 10, 11, 12}
PID 53203: ooo------oooo-------
53204: closing 3 and 4
53204: closing 5 and 6
53200: closing 7 and 8
53204: closing 7 and 8
53204: closing 9 and 10
53200: closing 9 and 10
PID 53204 (PPID 53200) i = 4: child at work
53200: closing 11 and 12
FD {11, 12, 13, 14}
53200: closing 13 and 14
PID 53200 (PPID 828): parent at work
FD {3, 4, 5, 6}
PID 53204: ooo--------oooo-----
PID 53200: ooooooo-------------
Opening bid: PID = 53200, PPID = 828, Node = 0 (PID 53200), Value = 4998
Writing opening bid to fd 6
Incoming bid: PID = 53201, PPID = 53200, Node = 0 (PID 53200), Value = 4998
PID: 53201, new offer 9207
Outgoing bid: PID = 53201, PPID = 53200, Node = 1 (PID 53201), Value = 9207
Incoming bid: PID = 53202, PPID = 53200, Node = 1 (PID 53201), Value = 9207
PID: 53202, new offer 6014
Outgoing bid: PID = 53202, PPID = 53200, Node = 1 (PID 53201), Value = 9207
Incoming bid: PID = 53203, PPID = 53200, Node = 1 (PID 53201), Value = 9207
53205: closing 5 and 6
PID: 53203, new offer 2821
Outgoing bid: PID = 53203, PPID = 53200, Node = 1 (PID 53201), Value = 9207
Incoming bid: PID = 53204, PPID = 53200, Node = 1 (PID 53201), Value = 9207
PID: 53204, new offer 9628
Outgoing bid: PID = 53204, PPID = 53200, Node = 4 (PID 53204), Value = 9628
53205: closing 7 and 8
53205: closing 9 and 10
53205: closing 11 and 12
PID 53205 (PPID 53200) i = 5: child at work
FD {13, 14, 3, 4}
PID 53205: ooooo--------oo-----
Incoming bid: PID = 53205, PPID = 53200, Node = 4 (PID 53204), Value = 9628
PID: 53205, new offer 6435
Outgoing bid: PID = 53205, PPID = 53200, Node = 4 (PID 53204), Value = 9628
Winning node: PID = 53200, PPID = 828, Node = 4 (PID 53204), Value = 9628
Final winner: PID = 53201, PPID = 53200, Node = 4 (PID 53204), Value = 9628
Final winner: PID = 53202, PPID = 53200, Node = 4 (PID 53204), Value = 9628
PID 53201: ooo-----------------
Final winner: PID = 53203, PPID = 53200, Node = 4 (PID 53204), Value = 9628
PID 53202: ooo-----------------
PID 53203: ooo-----------------
Final winner: PID = 53204, PPID = 53200, Node = 4 (PID 53204), Value = 9628
Final winner: PID = 53205, PPID = 53200, Node = 4 (PID 53204), Value = 9628
PID 53204: ooo-----------------
PID 53205: ooo-----------------
Recirculated: PID = 53200, PPID = 828, Node = 4 (PID 53204), Value = 9628
PID 53200: child 53201 exited 0x0100
PID 53200: child 53203 exited 0x0300
PID 53200: child 53202 exited 0x0200
PID 53200: child 53204 exited 0x0400
PID 53200: child 53205 exited 0x0500
PID 53200: ooo-----------------
$
Note that the code is careful to close unnecessary file descriptors before calling the be_childish() or be_parental() functions. The program works OK without those loops.

Related

Multiple 1-to-1 pipes in C

Is it possible in C to have multiple concurrent 1-to-1 pipes?
My example use case is the following:
The parent creates x children processes using fork()
The parent creates x pipes, one for each child
Each child write to its respective pipe, then closes it.
The parent reads from the pipes then closes them.
My current draft attempt is as follows however I have doubts about its functionality:
// Create x pipes
int fd[2*x];
pipe(fd);
// In child i do (i from 0 to x-1 inclusive):
close(fd[2*i]);
write(fd[2*i +1], .....);
close(fd[2*i +1]);
// In parent do:
wait() // wait for children to finish
// while any pipe has content do:
// For each i from 0 to x-1 inclusive:
close(fd[2*i +1]);
read(fd[2*i], .....);
close(fd[2*i]);
I would really appreciate it if someone could show me a simple example of this concept at work. The end goal here is one way conversations between children to parent with multiple values that the parent will store into a single array.
This code more or less does what you want. It uses error reporting code that is available in my SOQ (Stack Overflow Questions) repository on GitHub as files stderr.c and stderr.h in the src/libsoq sub-directory.
#include "stderr.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
enum { NUM_CHILDREN = 5 };
enum { MSG_BUFFSIZE = 64 };
static void be_childish(int kid, int *fd);
int main(int argc, char **argv)
{
int fd[2 * NUM_CHILDREN];
int pid[NUM_CHILDREN];
err_setarg0(argv[0]);
err_setlogopts(ERR_PID);
if (argc != 1)
err_usage("");
for (int i = 0; i < NUM_CHILDREN; i++)
{
if (pipe(&fd[2 * i]) != 0)
err_syserr("failed to create pipe for child %d: ", i);
}
for (int i = 0; i < NUM_CHILDREN; i++)
{
if ((pid[i] = fork()) < 0)
err_syserr("failed to fork child %d: ", i);
else if (pid[i] == 0)
be_childish(i, fd);
else
{
printf("Child %d has PID %d\n", i, pid[i]);
fflush(stdout);
}
}
char buffer[MSG_BUFFSIZE];
for (int i = 0; i < NUM_CHILDREN; i++)
{
close(fd[2 * i + 1]);
int pipe_in = fd[2 * i + 0];
int nbytes = read(pipe_in, buffer, sizeof(buffer));
if (nbytes < 0)
err_syserr("failed to read from FD %2d: ", pipe_in);
printf("Got %2d bytes [%.*s] from FD %2d, PID %d\n",
nbytes, nbytes, buffer, pipe_in, pid[i]);
close(pipe_in);
}
for (int i = 0; i < NUM_CHILDREN; i++)
{
int status;
int corpse = wait(&status);
if (corpse > 0)
printf("Child with PID %d exited with status 0x%.4X\n", corpse, status);
else
err_syserr("Failed to wait for dead children: ");
}
return 0;
}
static void be_childish(int kid, int *fd)
{
for (int i = 0; i < kid; i++)
{
close(fd[2 * i + 0]);
close(fd[2 * i + 1]);
}
close(fd[2 * kid + 0]);
int estat = kid + 32;
char buffer[MSG_BUFFSIZE];
int nbytes = snprintf(buffer, sizeof(buffer),
"Child %d (PID %d) exiting with status %d",
kid, (int)getpid(), estat);
int pipe_out = fd[2 * kid + 1];
if (write(pipe_out, buffer, nbytes) != nbytes)
err_syserr("failed to write to parent: ");
close(pipe_out);
exit(estat);
}
Sample run:
Child 0 has PID 36957
Child 1 has PID 36958
Child 2 has PID 36959
Child 3 has PID 36960
Child 4 has PID 36961
Got 42 bytes [Child 0 (PID 36957) exiting with status 32] from FD 3, PID 36957
Got 42 bytes [Child 1 (PID 36958) exiting with status 33] from FD 5, PID 36958
Got 42 bytes [Child 2 (PID 36959) exiting with status 34] from FD 7, PID 36959
Got 42 bytes [Child 3 (PID 36960) exiting with status 35] from FD 9, PID 36960
Got 42 bytes [Child 4 (PID 36961) exiting with status 36] from FD 11, PID 36961
Child with PID 36960 exited with status 0x2300
Child with PID 36959 exited with status 0x2200
Child with PID 36958 exited with status 0x2100
Child with PID 36957 exited with status 0x2000
Child with PID 36961 exited with status 0x2400

Set child pid to 0 but output others

I read such a snippet of code from an instruction
#include "apue.h"
int globvar = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";
int main(void)
{
int var;
pid_t pid; /* automatic variable on the stack */
var = 88; if (write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) - 1)
err_sys("write error");
printf("before fork\n"); /* we don’t flush stdout */
if ((pid = fork()) < 0) {
err_sys("fork error");
} else if (pid == 0) { /* child */
globvar++; /* modify variables */
var++;
} else {
sleep(2); /* parent */
}
printf("pid = %ld, glob = %d, var = %d, bufsize = %lu\n", (long)getpid(), globvar, var, sizeof(buf));
exit(0);
}
Run it and get outputs
$ ./a.out
a write to stdout
before fork
pid = 7310, glob = 7, var = 89, bufsize = 19 #child’s variables were changed
pid = 7309, glob = 6, var = 88, bufsize = 19 #parent’s copy was not changed
I am confused about the child's pid
if ((pid = fork()) < 0)
the pid is set as 0, but in the output it's pid is 7310.
How could that happen?
does the pid here is just a number rather than a process?
fork() returns 0 in the child process, but in the printf statement you are printing the pid using getpid() which is the actual pid of the child process.
If you had used pid in the printf statement instead of getpid() you will see that it prints 0.

Not sure why 1 printf statement prints twice

UPDATE
I thought this code block was giving me an error printing a printf statement out twice, but I commented out everything in my code BESIDES this and it worked just fine! What seems to be the issue then is the work I am doing with process IDs.
Here is the entire code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
pid_t pid, pid1;
int n;
int temp;
int stop = 1;
if (argc == 1) {
fprintf(stderr,"Usage: ./a.out <starting value>\n");
return -1;
}
n = atoi(argv[1]);
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
pid1 = getpid();
printf("child: pid = %d\n", pid);
printf("child: pid1 = %d\n", pid1);
}
else { /* parent process */
pid1 = getpid();
printf("parent: pid = %d\n", pid);
printf("parent: pid1 = %d\n", pid1);
wait(NULL);
}
while (n!=1) {
if (n%2 == 0) {
printf("%d, ", n);
temp = (n/2);
n = temp;
}else {
printf("%d, ", n);
temp = (3*n+1);
n = temp;
}
}
printf("1\n");
return 0;
}
The output I'm expecting is something like:
parent: pid = 1444
parent: pid1 = 1443
child: pid = 0
child: pid = 1444
8, 4, 2, 1
But instead I get this Output:
parent: pid = 1444
parent: pid1 = 1443
child: pid = 0
child: pid = 1444
8, 4, 2, 1
8, 4, 2, 1
Might a child a parent process be printing out the sequence a second time?
Yes, once the parent process has wait()ed on the child process, it continues down the code path and prints the sequence.
What you want is:
// ....
else if (pid == 0) { /* child process */
pid1 = getpid();
printf("child: pid = %d\n", pid);
printf("child: pid1 = %d\n", pid1);
while (n!=1) {
if (n%2 == 0) {
printf("%d, ", n);
temp = (n/2);
n = temp;
}else {
printf("%d, ", n);
temp = (3*n+1);
n = temp;
}
}
} else { /* parent process */
pid1 = getpid();
printf("parent: pid = %d\n", pid);
printf("parent: pid1 = %d\n", pid1);
wait(NULL);
}
After
wait(NULL);
You need an exit/return. The parent has done its job of bringing up the child and is done

Forking N processes in chain

I want to solve a certain problem and i can't figure it out how to do it properly. I have to create N processes in chain and after i finish making all of them, the initial process will random a number and write it in the pipe, the other processes read from the pipe the number, they randomize a number and substract the result from the number read, write it back to the pipe and so on. Here is what i've tried
#include <string.h>
#include <sys/types.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#define P_READ 0
#define P_WRITE 1
void forker(int nprocesses, int** pipes, int fd[2])
{
pid_t pid;
int buf;
if(nprocesses > 0)
{
if ((pid = fork()) < 0)
{
perror("fork");
}
else if (pid == 0)
{
//Child
printf("Child %d created PID : %d , PPID : %d\n", nprocesses-1, getpid(), getppid());
int i = nprocesses - 1;
time_t t;
srand((int)time(&t) % getpid()); // get unique seed for every child
int r = (rand() % 11) + 10;
if (i==0) {
read(fd[P_READ], &buf, sizeof(int));
close(fd[P_READ]);
}else{
read(pipes[i-1][P_READ], &buf, sizeof(int));
close(pipes[i-1][P_READ]);
}
close(pipes[i][P_READ]);
buf -= r;
printf("%d|%d|%d|%d\n", buf, r, getpid(), getppid());
write(pipes[i][P_WRITE], &buf, sizeof(int)); // write
close(pipes[i][P_WRITE]);
printf("Child %d end\n", nprocesses-1);
}
else if(pid > 0)
{
forker(nprocesses - 1, pipes, fd);
}
}
}
int main (void)
{
int status = 0;
srand(time(NULL));
pid_t pid = getpid();
pid_t parent = getpid();
pid_t wpid;
int n, fd[2], buf;
printf("Please enter how many processes you want(between 6 and 15): ");
scanf("%d", &n);
while ( n < 6 || n > 15)
scanf("%d", &n);
int **pipes = (int **)malloc(n * sizeof(int*));
for(int i = 0; i < n; i++) pipes[i] = (int *)malloc(2 * sizeof(int));
printf("I'm parent - my pid is %d\n",pid);
pipe(fd);
for(int i=0; i<n; i++) {
if(pipe(pipes[i])) {
printf("pipe error");
return -1;
}
}
forker(n, pipes, fd);
if(parent == getpid()) {
close(fd[P_READ]);
buf = (rand() % 9001) + 1000;
printf("The initial number is %d created by process with pid : %d\n", buf, getpid());
write(fd[P_WRITE], &buf, sizeof(int));
close(fd[P_WRITE]);
}
while ((wpid = wait(&status)) > 0); // WAIT
if (pid == getpid()) printf("End of parent and my pid was %d\n", pid);
return 0;
}
The output looks something like this :
Please enter how many processes you want(between 6 and 15): 10
I'm parent - my pid is 3827
Child 9 created PID : 3828 , PPID : 3827
Child 8 created PID : 3829 , PPID : 3827
Child 7 created PID : 3830 , PPID : 3827
Child 6 created PID : 3831 , PPID : 3827
Child 5 created PID : 3832 , PPID : 3827
Child 2 created PID : 3835 , PPID : 3827
Child 3 created PID : 3834 , PPID : 3827
The initial number is 1625 created by process with pid : 3827
Child 1 created PID : 3836 , PPID : 3827
Child 4 created PID : 3833 , PPID : 3827
Child 0 created PID : 3837 , PPID : 3827
1609|16|3837|3827
Child 0 end
1589|20|3836|3827
1573|16|3835|3827
Child 2 end
1559|14|3834|3827
Child 3 end
1543|16|3833|3827
Child 4 end
1530|13|3832|3827
Child 5 end
Child 1 end
1511|19|3831|3827
Child 6 end
1498|13|3830|3827
Child 7 end
1488|10|3829|3827
Child 8 end
1470|18|3828|3827
Child 9 end
End of parent and my pid was 3827
The problem is that, i am not sure if the first number is randomed before the processes creation(but that's not the big issue here). The big issue is that the initial process creates all the child processes and it is not "in chain".
First fork you process N times, then generate the random number and pass it to other process.
So put the creation of the random number outside the loop for forking the main process

Wait() runs twice?

In my code below, I'm running a parent process which forks off into two child processes. After child(getpid());, both children exit with a status.
However, when I run the parent process, it somehow always decides to run the parent section twice (sets two different pid values), and I just can't get it to run just once. Is there a way to make wait stop after getting one value?
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
void child(int n) { //n: child pid
printf("\nPID of child: %i \n", n);
//random number rand
int randFile = open("/dev/random", O_RDONLY);
int r;
if(rand < 0)
printf("ERROR: %s\n", strerror(errno));
else {
unsigned int seed;
read(randFile, &seed, 4); //&rand is a pointer, 4 bytes
int randClose = close(randFile);
srand(seed); //seeds rand() with random from /dev/random
r = rand();
if(randClose < 0)
printf("ERROR: %s\n", strerror(errno));
//range between 5 and 20 seconds
r = r % 20;
if( r < 5)
r = 5;
}
// printf("\n%i\n", r);
sleep(r);
// sleep(1);
printf("\n child with pid %i FINISHED\n", n);
exit( r );
}
int main() {
printf("\nPREFORK\n");
int parentPID = getpid();
int child0 = fork();
if(child0 < 0)
printf("ERROR: %s\n", strerror(errno));
int child1 = fork();
if(child1 < 0)
printf("\nERROR: %s\n", strerror(errno));
if(getpid() == parentPID)
printf("\nPOSTFORK\n");
//if children
if(child1 == 0) //using child1 as child-testing value b/c when child1 is set, both children are already forked
child(getpid());
int status;
int pid = wait(&status);
//parent
if(getpid() != 0) {
if( pid < 0)
printf("\nERROR: %s\n", strerror(errno));
if ( pid > 0 && pid != parentPID) {
printf("\nPID of FINISHED CHILD: %i\n Asleep for %i seconds\n", pid, WEXITSTATUS(status));
printf("PARENT ENDED. PROGRAM TERMINATING");
}
}
return 0;
}
The parent is doing:
int child0 = fork(); // + test if fork failed
int child1 = fork(); // + test if fork failed
First you only have the parent.
After 1st fork you have the parent and the 1st child, both at the same execution point, so just before the next fork.
So just after that the parent re-creates a child, and the 1st child creates its own child (and will act like the parent).
You have to use if/else so that you are sure that the child don't fork. i.e.:
child0 = fork(); // add check for errors
if (child0 == 0) {
// the 1st child just have to call that
child(getpid());
exit(0);
}
// here we are the parent
child1 = fork();
if (child1 == 0) {
// the 2nd child just have to call that
child(getpid());
exit(0);
}
You can do that differently, of course, this is just an example. The main point is to not call fork() within the child.

Resources