Pass a value between processes using pipes in a loop - c

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?

Related

Implementation of multiple pipelines in C

First, I Saw already the all posts before. I took already a code from here https://stackoverflow.com/a/8439286/14888108
I have a problem I didn't know how to solve: when I do fork the pid is not 0 no matter what.
its a random number started like : 4013,4014 if I give [input: echo atb | grep "b"]
Here is my code:
EDITED AFFTER MISTAKE IN THE CODE SAME PROBLEM:
void Pipeline(char *input) {
int numPipes = 2 * countPipes(input);
int k = commends(input);
int j = 0;
for (int i = 0; i < k; i++) {
int pid = fork();
if (pid == 0) {
if (i != k-1) {
if (dup2(pipefds[j + 1], 1) < 0) {
perror("dup2");
exit(EXIT_FAILURE);
}
}
//if not first command&& j!= 2*numPipes
if (j != 2*numPipes && i != 0) {
if (dup2(pipefds[j - 2], 0) < 0) {
perror(" dup2");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 2 * numPipes; i++) {
close(pipefds[i]);
}
if (execvp(vec[i], vec) < 0) {
perror(vec[i]);
exit(EXIT_FAILURE);
}
} else if (pid < 0) {
prev++;
perror("error");
exit(EXIT_FAILURE);
}
j += 2;
}
for (int i = 0; i < 2 * numPipes; i++) {
close(pipefds[i]);
}
for (int i = 0; i < numPipes + 1; i++) {
wait(NULL);
}
printf("DONE!\n");
}
These lines:
int pid = fork();
prev = pid;
if (pid == prev+1) {
don't seem to make a lot of sense. If you copy pid into prev first, how can pid then ever be equal to prev + 1?
Also, you seem to be expecting a particular sequence of process id:s, that is not very likely or portable (or even nice). Other processes are busy creating and destroying processes in the background, I don't think you can assume that your particular process has a private pid space to fill.

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

Multiple processes with pipe, unexpected variable change?

I know it sounds unreal "unexpected variable change." Since I couldn't spot the problem I used that title...
Firstly, this is my homework. The homework is about reading two matrices from file then create 4 child processes, parent will send (via pipe) the quarter pieces of matrix to child processes. Child process will make their calculations afterwards they will send the calculated indices back to parent process(via pipe again. Trying to achieve bidirectional pipes here.) so parent will print calculated values to stdout and return.
Currently what I have done is read those matrices from file, created 3 processes(was going step by step), send 1/4 of matrices to each 3 processes and tried to check if i succeeded or not.
The problem is "generally" what happens is either I see third_start variable is changed (in the same scope) therefore it doesn't even enter the loop.
Also I observed couple more things;
When redirecting the output to some file the data is looks like %10 of my program written there.
If I supply the matrix with smaller values like 4x4 matrices. The problem with third_start doesn't happen.
I'm sure that I'm doing something stupid.
Here is related part of my code. (Bit messy, it's not the way I send my homeworks.. Please ignore the calculations about matrices.)
int pipe_fds[2]; //first pipe
int pipe_fds2[2];//second pipe
int pipe_fds3[2];//third pipe
int pipe_fds4[2];//fourth pipe
int pip_ret, pip_ret2, pip_ret3, pip_ret4;
int pid2,pid3,pid4,pid5; //assumed p1 is parent and 2,3,4,5 are child processes.
int single_x; //store single_x val;
int single_y;
pip_ret = pipe(pipe_fds);
pid2 = fork();
if(pip_ret == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe\n");
exit(1);
}
else if(pid2 == 0)
{
if (close(pipe_fds[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int first_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int first_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(read(pipe_fds[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
first_quarter_x[i][j] = single_x;
if(read(pipe_fds[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
first_quarter_y[i][j] = single_y;
fprintf(stderr,"(2)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(2)Child with pid %d received value %d\n",getpid(), single_y);
}
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(matrixA[i][j] == first_quarter_x[i][j])
{
fprintf(stderr,"Good2a\n" );
}
else
{
fprintf(stderr,"Bad2a.\n" );
}
}
fprintf(stderr,"\n" );
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(matrixB[i][j] == first_quarter_y[i][j])
{
printf("Good2b\n" );
}
else
{
printf("Bad2b.\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
pip_ret2 = pipe(pipe_fds2);
pid3 = fork();
if(pip_ret2 == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe for 3.process\n");
exit(1);
}
else if(pid3 == 0)
{
if (close(pipe_fds2[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int second_start = _pow(2, n) / 2;
int second_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int second_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n); ++j)
{
if(read(pipe_fds2[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
second_quarter_x[i][j] = single_x;
if(read(pipe_fds2[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
second_quarter_y[i][j] = single_y;
fprintf(stderr,"(3)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(3)Child with pid %d received value %d\n",getpid(), single_y);
}
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n) ; ++j)
{
if(second_quarter_x[i][j] == matrixA[i][j])
{
fprintf(stderr,"Good3a \n" );
}
else
{
fprintf(stderr,"Bad3a\n" );
}
}
fprintf(stderr,"\n" );
}
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = second_start ; j < _pow(2, n) ; ++j)
{
if(second_quarter_y[i][j] == matrixB[i][j])
{
fprintf(stderr,"Good3b \n" );
}
else
{
fprintf(stderr,"Bad3b\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
pip_ret3 = pipe(pipe_fds3);
pid4 = fork();
if(pip_ret3 == -1)
{
fprintf(stderr, "%s\n", "Unable to create pipe for 4.process\n");
exit(1);
}
else if(pid4 == 0)
{
if (close(pipe_fds3[1]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int third_start = _pow(2, n) / 2;
printf("THIRD START IS %d\n",third_start ); //here it prints normal.
int third_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int third_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(read(pipe_fds3[0], &single_x, sizeof(single_x)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
third_quarter_x[i][j] = single_x;
if(read(pipe_fds3[0], &single_y, sizeof(single_y)) <= 0)
{
perror("read failed ");
exit(EXIT_FAILURE);
}
third_quarter_y[i][j] = single_y;
fprintf(stderr,"(4)Child with pid %d received value %d\n",getpid(), single_x);
fprintf(stderr,"(4)Child with pid %d received value %d\n",getpid(), single_y);
}
}
printf("THIRD START IS %d\n",third_start ); //then it prints something anormal...
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(third_quarter_x[i][j] == matrixA[i][j])
{
fprintf(stderr,"Good4a \n" );
}
else
{
fprintf(stderr,"Bad4a\n" );
}
}
printf("\n" );
}
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
if(third_quarter_x[i][j] == matrixB[i][j])
{
fprintf(stderr,"Good4b \n" );
}
else
{
fprintf(stderr,"Bad4b\n" );
}
}
fprintf(stderr,"\n" );
}
exit(EXIT_SUCCESS);
}
//parent start
if (close(pipe_fds[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
fprintf(stderr,"First quarter beginning \n");
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds[1], &single_x, sizeof(single_x));
write(pipe_fds[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 2 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 2 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"First quarter end\n \n");
fprintf(stderr,"Second quarter beginning\n");
if (close(pipe_fds2[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int sec = _pow(2,n) / 2;
for(i = 0 ; i < _pow(2, n) / 2 ; ++i)
{
for(j = sec ; j < _pow(2, n); ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds2[1], &single_x, sizeof(single_x));
write(pipe_fds2[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 3 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 3 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"Second quarter end\n");
fprintf(stderr,"Third quarter beginning\n");
if (close(pipe_fds3[0]) == -1)
{
perror("close");
exit(EXIT_FAILURE);
}
int third = _pow(2,n) / 2;
for(i = third ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
single_x = matrixA[i][j];
single_y = matrixB[i][j];
write(pipe_fds3[1], &single_x, sizeof(single_x));
write(pipe_fds3[1], &single_y, sizeof(single_y));
fprintf(stderr,"Parent with pid %d sent value to 4 %d\n",getpid(), single_x);
fprintf(stderr,"Parent with pid %d sent value to 4 %d\n",getpid(), single_y);
}
}
wait(NULL);
fprintf(stderr,"Third quarter end\n");
int pipe_fds2[2];//second pipe
Indirect help: numbered variables are almost always better represented as arrays. You probably want an array of structures
struct child_t {
int datapipe[2], resultpipe[2];
pid_t pid;
int result;
} children[4];
Now you can iterate over your array, and for each element call pipe and fork. Each child deals only with its pipe, but the parent can iterate over all children. In a matrix, I imagine it matters which part of the matrix produces which result, and this structure would keep those pieces of information related.
By organizing your data that way, you eliminate the temptation to duplicate code, because a loop on an array is easier. Less code means fewer bugs, so you get your homework done sooner.
You're accessing outside the arrays.
int third_start = _pow(2, n) / 2;
printf("THIRD START IS %d\n",third_start ); //here it prints normal.
int third_quarter_x[_pow(2, n) / 2][_pow(2, n) / 2];
int third_quarter_y[_pow(2, n) / 2][_pow(2, n) / 2];
The indexes of both dimensions of third_quarter_x and third_quarter_y go from 0 to third_start-1. But then you have the following loops:
for(i = third_start ; i < _pow(2, n) ; ++i)
{
for(j = 0 ; j < _pow(2, n) / 2; ++j)
{
The values of i are outside the range of indexes for the first dimension. Since you're writing outside the array, you're causing undefined behavior.
The loops should both go from 0 to third_start.
You have a similar problem in the previous process with second_start, except it's doing it in the j loop.

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

Categories

Resources