Forking in loop results in weird behavior - c

I have the following snippet of C code:
int i;
printf("ncams: %d\n", ncams);
for (i = 0; i < ncams; i++) {
int *pips_fds = malloc(2 * sizeof(int));
pid_t pid;
pipe(pips_fds);
printf("cproc_count in parent: %d, counter i: %d\n", cproc_count, i);// cproc_count is a variable declared above in code
if ( (pid = fork())== -1) {
logerr_r("cannot fork");
} else if (pid == 0) {
if ( close(pips_fds[1]) < 0) {
logerr_r("cannot close pipe");
}
printf("cproc_count in child: %d, counter i: %d\n", cproc_count, i);
int j;
for (j = 0; j < i; j++) {
free_cproc_id(cprocs[i]);//I don't need this in child process.
}
free(cprocs);// I don't need it also here in child process.
} else {
CProcID *cproc = malloc(sizeof(CProcID));
cproc->id = ++cproc_count;
cproc->pipes = pips_fds;
if (close(pips_fds[0]) < 0) {
logerr_r("cannot close pipe");
}
cprocs[i] = cproc;
}
}
Now, the output from this is:
ncams: 2
cproc_count in parent: 0, counter i: 0
cproc_count in parent: 1, counter i: 1
cproc_count in child: 1, counter i: 1
cproc_count in child: 0, counter i: 0
cproc_count in parent: 0, counter i: 1
cproc_count in child: 0, counter i: 1
As you can see, I have i = 1 for two times in parent. Can anybody tell me what I'm doing wrong?

The reason you have cproc_count in parent: 0, counter i: 1 being printed twice is because it is printed once by the parent, and then printed again by the child after the child has exited it's else if branch and looped around. You probably want to break out of the outer for within the child else if branch so that the child process doesn't also continue looping and forking new children.

Related

fork() and pipe() in C goes wrong

I am learning about fork and pipe but have a problem with the following: My aim was to build a program with 3 processes and I did that but my question is: Why does printf("Sum of first half: %d\n", sum); get executed twice?
I checked the code for any logical errors that I made but couldn't find anything.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int size = sizeof(arr) / sizeof(int);
int sum;
int fd[2];
pipe(fd);
int id = fork();
if (id == 0) // Child process
{
for (int i = 0; i < size / 2; i++)
sum = sum + arr[i];
int j = fork();
if (j == 0)
{
printf("Hello I'm the grandchild\n");
}
}
else // Parent process
{
for (int i = size / 2; i < size; i++)
sum = sum + arr[i];
}
if (id == 0) // Child process writing to the pipe
{
close(fd[0]);
write(fd[1], &sum, sizeof(sum));
close(fd[0]);
printf("Sum of first half: %d\n", sum);
}
else // Parent process reading from the pipe
{
int x;
close(fd[1]);
read(fd[0], &x, sizeof(sum));
close(fd[1]);
printf("Sum of second half: %d\n", sum);
printf("Total sum: %d\n", x + sum);
}
}
Your code simplified:
int main()
{
int id = fork();
if (id == 0)
fork();
if (id == 0)
printf("Sum of first half\n");
else
printf("Sum of second half\n");
}
And the explanation:
code
Parent
Child
Granchild
fork()
fork
N/A
N/A
id value
id != 0
id==0
N/A
if (id == 0) fork()
then not executed
fork
N/A
id value
id != 0
id == 0
id == 0
if (id == 0) printf("sum first")
then not executed
printf
printf
else printf("sum second half")
printf
else not executed
else not executed

Pass a value between processes using pipes in a loop

I am trying to build a program that forks 4 child processes. The first child takes a value declared before forking, decrements it then passes it through a tube to the second process. The latter increments the value and passes it to the third one. 3 -> 4, 4 - 1 and so on. The program will end when 0 is reached and exit with the PID of the child that got that 0.
This is what I tried:
volatile sig_atomic_t end = 1;
First I installed a signal handler:
void sighandler(int sig)
{
(void)sig;
end = 0;
}
Then I assigned the action to SIGUSR1:
void prepare()
{
struct sigaction s;
s.sa_handler = sighandler;
s.sa_flags = 0;
sigemptyset(&s.sa_mask);
sigaddset(&s.sa_mask, SIGUSR1);
sigaction(SIGUSR1, &s, NULL);
}
This is my main:
int main()
{
pid_t cpid, first;
int status;
int COUNT = 10;
int pipes[NPROC];
prepare();
for (int i = 0; i < 2; i++)
{
pipe(pipes + 2 * i);
}
for (int i = 0; i < NPROC; i++)
{
switch (first = fork())
{
case -1:
perror("fail");
case 0:
if (i % 2 == 0)
{
while (end)
{
dup2(pipes[i], 0);
read(pipes[i], &COUNT, sizeof(COUNT));
COUNT--;
if (COUNT < 0)
kill(getppid(), SIGUSR1);
dup2(pipes[i + 1], 1);
write(pipes[i + 1], &COUNT, sizeof(COUNT));
for (int j = 0; j < NPROC; j++)
close(pipes[j]);
}
}
else
{
while (end)
{
dup2(pipes[i - 1], 0);
read(pipes[i - 1], &COUNT, sizeof(COUNT));
COUNT--;
if (COUNT < 0)
kill(getppid(), SIGUSR1);
dup2(pipes[(i + 2) % NPROC], 1);
write(pipes[(i + 2) % NPROC], &COUNT, sizeof(COUNT));
for (int j = 0; j < NPROC; j++)
close(pipes[j]);
}
}
exit(i);
}
printf("Start %d \n", first);
}
for (int i = 0; i < NPROC; ++i)
{
cpid = wait(&status);
if (!WIFEXITED(status))
printf("Error in child %d\n", (int)cpid);
else
printf("Finished %d\n", (int)cpid);
}
return EXIT_SUCCESS;
}
The idea is, the program runs, installs the signal handler. The signal handler will, when triggered, stop all children processes and allow them to exit.
Then I fork 4 processes. Each will open and close certain tubes in order to communicate with each other and at the same time, each decrements the value and pass it along. When the value hits 0 a signal will be raised and we will get the process id that sent the signal.
When I run the program, it starts and then it just waits indefinitely...
What am I missing?

How to fork only with a specific child?

I am trying to build a process tree like this:
P1
/ \
P3 P2
\
P4
\
....
But i couldn't make it work. I tried this but it only forks with P1.
for(int i = 0; i < depth; i++) {
int _pid = fork();
if(_pid == 0) {
printf("[son] pid %d from [parent] pid %d\n", getpid(), getppid());
exit(0);
}
}
wait(NULL);
The requirement to use only one fork call makes the solution cumbersome and ugly, but still doable like this:
Step 1: create an inner loop that will run twice if i is 0, and once for any i > 0.
Step 2: fork only in the child process after the first iteration of the outer loop.
Step 3: exit the child that was forked on the second iteration of the inner loop.
int cur_pid = 0;
printf("Root PID %d started by %d\n", getpid(), getppid());
for (int i = 0; i < depth && cur_pid == 0; i++) {
for (int j = 0; j < (i ? 1 : 2); j++) {
cur_pid = fork();
if (cur_pid == 0) {
printf("[son] pid %d from [parent] pid %d\n", getpid(), getppid());
if (j == 1) {
exit(0);
} else {
break;
}
} else if (cur_pid < 0) {
printf("Error forking at PID %d\n", getpid());
}
}
}
wait(NULL);
Remember to wait on the child process of every iteration if you want getppid to return valid values!

passing 2D Array to recursion

I am trying to make calculations with using fork in C.
I have a 2D array with members {1,2,3,4}, I have a function to get square for each member in the array. I will call this function with child processes.
For example for 3 child process output will be like this;
1.Child
1 4
9 16
----------
2.Child
1 16
81 256
----------
3.Child
1 256
6561 65536
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int matrix[2][2] = {1, 2, 3 ,4 } ;
int main(){
forkFork(3);
}
void forkFork(int counter)
{
pid_t pid;
if(counter == 0)
{
exit(0);
}
if(counter > 0)
{
if ((pid = fork()) < 0)
{
perror("fork error :(");
}
else if (pid == 0)
{
matrixPower(matrix);
print(matrix);
}
else if(pid > 0)
{
forkFork(counter - 1);
}
}
}
void matrixPower(int m[2][2])
{
int i,j,k;
int result = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
result = matrix[i][j]*matrix[i][j];
m[i][j] = result;
result = 0;
}
}
}
void print(int a[2][2])
{
int row, col ;
for( row = 0; row < 2; row++ )
{
for( col = 0; col < 2 ; col++ )
{
printf("%d\t", a[row][col]);
}
puts("");
}
printf("-------------------------------\n");
}
I could not find a way to pass new array to recursion function...
The problem with your solution is that all forked processes are created by the main/parent process. Therefore, each forked process just inherits the address space of the parent whose matrix values are always {1, 2, 3, 4}. The solution is for each modifying process to create its child process. Thus a new child process inherits the modified matrix.
See my solution below for forkFork function which works as expected.
void forkFork(int counter)
{
pid_t pid;
if(counter == 0)
{
exit(0);
}
if(counter > 0)
{
if ((pid = fork()) < 0)
{
perror("fork error :(");
}
else if (pid == 0)
{
matrixPower(matrix);
print(matrix);
forkFork(counter - 1);
}
}
}

Creating multiple processes in C

I am writing a program that needs to create multiple processes. Let's say this number is 3. I want each of these processes to count and output from 1 to 5, and to sleep for 1 second between each count/output. I tried to do that in a following manner, but my sleep(1) did not work like it was being interrupted. I would appreciate some background on the topic, what i did wrong, and how to resolve this. Here is my code so far.
/*
* Creates N > 2 processes.
*/
int main(int argc, const char * argv[])
{
pid_t pid;
for(int i = 0; i < N_PROC; i++) {
pid = fork();
if(pid == 0) {
ProcessWork();
exit(0);
}
}
}
/*
* Work of a single process.
*/
void ProcessWork() {
char buffer[BUF_SIZE];
for (int i = 1; i <= 5; i++) {
sleep(1);
sprintf(buffer, "PID = %d, count = %d\n", getpid(), i);
write(1, buffer, strlen(buffer));
}
}
Your sleep() works exactly as it should work. However, your problem seems to be that the parent process does not wait for the termination of the child processes, so the parent process terminates before the children have performed the work. Thus, it looks like this on a Unix system:
% ./a.out
% PID = 41431, count = 1
PID = 41430, count = 1
PID = 41432, count = 1
PID = 41431, count = 2
PID = 41430, count = 2
PID = 41432, count = 2
PID = 41430, count = 3
PID = 41431, count = 3
PID = 41432, count = 3
PID = 41430, count = 4
PID = 41431, count = 4
PID = 41432, count = 4
PID = 41431, count = 5
PID = 41430, count = 5
PID = 41432, count = 5
You should take a look at the manual page of the wait() system call. You can call that system call in a loop, and it returns the pid of the terminated child as long as there are children, and -1 with errno == ECHILD once you've run out of children. That ECHILD can be used as the loop termination criterion.
Wait for forked process termination, if I understood your problem...
int main(int argc, const char * argv[])
{
pid_t pid[N_PROC];
for(int i = 0; i < N_PROC; i++) {
pid_t cur_pid = fork();
if(cur_pid == 0) {
pid[i] = cur_pid;
ProcessWork();
exit(0);
}
}
for(int i = 0; i < N_PROC; i++)
wait(&pid[i]);
}

Resources