How to differentiate child processes? - c

Say I fork N children. I want to create pipes between 1 and 2, 2 and 3, 4 and 5, ... and so on. So I need some way to figure out which child is which. The code below is what I currently have. I just need some way to tell that child number n, is child number n.
int fd[5][2];
int i;
for(i=0; i<5; i++)
{
pipe(fd[i]);
}
int pid = fork();
if(pid == 0)
{
}

The following code will create a pipe for each child, fork the process as many times as it is needed and send from the parent to each child an int value (the id we want to give to the child), finally the children will read the value and terminate.
Note: since you are forking, the i variable will contain the iteration number, if the iteration number is the child id, then you do not need to use pipe.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int count = 3;
int fd[count][2];
int pid[count];
// create pipe descriptors
for (int i = 0; i < count; i++) {
pipe(fd[i]);
// fork() returns 0 for child process, child-pid for parent process.
pid[i] = fork();
if (pid[i] != 0) {
// parent: writing only, so close read-descriptor.
close(fd[i][0]);
// send the childID on the write-descriptor.
write(fd[i][1], &i, sizeof(i));
printf("Parent(%d) send childID: %d\n", getpid(), i);
// close the write descriptor
close(fd[i][1]);
} else {
// child: reading only, so close the write-descriptor
close(fd[i][1]);
// now read the data (will block)
int id;
read(fd[i][0], &id, sizeof(id));
// in case the id is just the iterator value, we can use that instead of reading data from the pipe
printf("%d Child(%d) received childID: %d\n", i, getpid(), id);
// close the read-descriptor
close(fd[i][0]);
//TODO cleanup fd that are not needed
break;
}
}
return 0;
}

Related

How to pass arguments from parent process to child process in Unix?

Inside my code I want to...
1) the parent process will create an array with at least 10
element
2) the child process will calculate the production of all elements
with odd index inside the array
3) the child process will provide the result
to the parent process when it finish calculation and then the child process
will terminate
4) the parent will calculate the production after it get the
result from the child process
5) the parent process will finally output
the results.
Now the CODE LOGIC is easy to write which is down below
int cal(int arr[10]) {
int i=0;
int sum = 0;
for (i=1; i<10; i=i+2) {
sum = sum + arr[i];
}
return sum;
} // end of calc
int main() {
int arr[] = { 10, 20, 25, 5, 6, 45, 87, 98, 23, 45};
int sum = cal(arr);
printf("Sum of all odd indexs element is : %d", sum);
return 0;
} // end of main
And here is the code for creating a child process using fork()
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid t pid;
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
execlp("/bin/ls","ls",NULL);
}
else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
printf("Child Complete");
}
return 0;
} // end of main
My questions are...
How would I use the CODE LOGIC and combine it with creation of the child process using fork()? If the pid == 0, then the creation of a child process was successful so I think that is where we insert the code for step 2... 2) the child process will calculate the production of all elements
with odd index inside the array.
How would the parent send the array to the child process so that the child process could sum the elements with odd index?
UPDATED CODE: I combined both codes above into one
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
/*
calculate the production of all elements with odd index inside the array
*/
int cal(int arr[10]) {
int i=0;
int sum = 0;
for (i=1; i<10; i=i+2) {
sum = sum + arr[i];
}
return sum;
} // end of calc
int main() {
pid t pid;
/* fork a child process */
pid = fork();
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
print("I am the child process");
// the child process will calculate the production
// of all elements with odd index inside the array
calc();
// the child process will provide the result to the parent process
// when it finish calculation and then the child process will terminate
exit(0);
}
else { /* parent process */
/* parent will wait for the child to complete */
printf("I am the parent, waiting for the child to end");
// the parent process will create an array with at least 10 element
int arr[] = { 1, 2, 5, 5, 6, 4, 8, 9, 23, 45 };
int sum = calc(arr);
wait(NULL);
printf("Child completed calculating the production of all elements with odd index inside the array");
// the parent will calculate the production after it get the result from the child process
// the parent process will finally output the results.
printf("Sum of all odd indexs element is : %d", sum);
}
return 0;
} // end of main
There are inter-process communication (IPC) mechanisms allowing you to pass information between processes.
As a rule, fork is the only way to create new processes in Unix-like systems. At that, child process inherits code and address space of parent. It means that child is a duplicate (in some degree, see link above) of parent at this point of time.
In modern Unix variants and in Linux, fork is implemented using copy-on-write pages. It just means that when parent or child process tries to modify shared memory page, operating system creates a copy of this page. Now parent and child have own memory page.
System call exec replaces the current process image with a new process image. It means that parent and child processes wouldn't share any memory pages or code now.
In your program you shouldn't call execlp(). Use advantages of copy-on-write mechanism. So do fork() in the main() function in your CODE LOGIC program after defining the arr. Then access arr from the child process. Use wait() system call to make parent is blocked until child doesn't finish.
You should use IPC to return result from the child process. In your case pipes are the best choice. But it's obvious you do lab assignment about Unix processes, and not about IPC. So you may return result via exit code of child process. Pass result to the exit() function. Note that you can pass only 8 bits (see comments under my answer).
This is a working code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int calc(int *arr, int n) {
int sum = 0;
for (i = 1; i < n; i += 2) {
sum = sum + arr[i];
}
return sum;
}
int main(void) {
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int n = sizeof(arr) / sizeof(arr[0]);
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
}
else if (pid == 0) {
printf("I am the child process\n");
int child_sum = calc(arr, n);
exit(child_sum);
}
else {
printf("I am the parent process\n");
int parent_sum = calc(arr, n);
int child_sum;
if (wait(&child_sum) == -1) {
perror("wait failed");
}
else {
printf("Sum by child: %d\n", child_sum);
}
printf("Sum by parent: %d\n", parent_sum);
}
return 0;
}
Here execlp will give your child process a new address space. So you practically can't send an argument to the child process from parent process. But you can do as follows,
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t pid;
/* fork a child process */
pid = fork();
int sum = 0;
int arr[] = { 10, 20, 25, 5, 6, 45, 87, 98, 23, 45};
if (pid < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) { /* child process */
int i=0;
for (i=1; i<10; i=i+2) {
sum = sum + arr[i];
}
return sum;
}
else { /* parent process */
/* parent will wait for the child to complete */
wait(NULL);
int i=0;
for (i=1; i<10; i=i+2) {
sum = sum + arr[i];
}
printf("%d\n",sum);
}
return 0;
}
ps-
Here the array is declared after the fork() so it is common to both parent and child processes.

read from a pipe is blocked after close writer

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int childs[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (pipe(p) == -1) { perror("pipe"); exit(1); }
pid_t pid = fork();
if (pid) {
close(p[0]);
childs[i] = p[1];
}
else {
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { ... }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(childs[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}
Output with comment:
child 1 start
child 2 start
child 3 start
child 3 read (0), finish
The next line is displayed after 2 seconds
child 2 read (0), finish
The next line is displayed after 2 seconds
child 1 read (0), finish
I do not write to the channel in the parent. Closing it, I want to give a signal to the child that will be waiting in the read.
It seems that there is a following. Сhild N expected finishes reading from the result 0, it's ok. Children 2 (N-1) and 1 are locked in a read to a child 3 is completed. Then the child 1 is similar will wait.
Why lock occur?
Child processes inherit open file descriptors from their parent. Your main process opens file descriptors in a loop (using pipe, keeping only the write ends). Child 1 inherits no descriptors (except for stdin/stdout/stderr); child 2 inherits childs[0] (the descriptor going to child 1); child 3 inherits childs[0] and childs[1] (the descriptors going to child 1 and 2).
read on a pipe blocks as long as any write descriptor is still open (because it could be used to send more data). So child 1 waits (because child 2 and child 3 still have an open write descriptor) and child 2 waits (because child 3 still has an open write descriptor); only child 3 sleeps and exits. This causes its file descriptors to close, which wakes up child 2. Then child 2 sleeps and exits, closing its file descriptors, which finally wakes up child 1.
If you want to avoid this behavior, you have to close the open file descriptors in each child:
else {
for (int j = 0; j < i; j++) {
close(childs[j]);
}
close(p[1]);
printf("child %d start\n", i + 1);
The write ends of the pipes are getting inherited by the children.
Since filedescriptor are ref-counted, the write end is only considered closed if all references to it are closed.
Below is your code, slightly refactored, with a fix added:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv) {
int children_w[3];
for (int i = 0; i < 3; ++i) {
int p[2];
if (0>pipe(p))
{ perror("pipe"); exit(1); }
pid_t pid;
if(0> (pid= fork()))
{ perror("fork"); exit(1); }
if(pid==0) {
/* Fix -- close the leaked write ends */
int j;
for(j=0; j<i; j++)
close(children_w[j]);
/* end fix*/
close(p[1]);
printf("child %d start\n", i + 1);
char buf[10];
buf[0] = 0;
int r;
if ((r = read(p[0], buf, 9)) == -1) { perror("read");/*...*/ }
printf("child %d read %s (%d), finish\n", i + 1, buf, r);
sleep(2);
exit(0);
}
children_w[i] = p[1];
close(p[0]);
}
for (int i = 0; i < 3; ++i) {
// if (argc > 1) {
// write(childs[i], "42", 2);
// }
// ============== HERE >>>
close(children_w[i]);
}
pid_t pid;
while ((pid = waitpid(-1, NULL, 0)) > 0) {
printf("child %d exited\n", pid);
}
return 0;
}

Synchronization of parent and child with SIGUSR signal in C. Make parent and child read one after the other

I have created a two way communication between parent and child processes using two pipes. Parent and child write data and I was able to make them read the data from each other. Parent writes numbers 1 to 5, and child writes numbers from 6 to 10. But I want parent to start reading data the first, and then reading continues in this order switching from parent to child until all the data are read: 6,1,7,2,8,3,9,4,10,5. I have tried to synchronize the reading with SIGUSR1 but when the parent is reading for the second time the program stops. I have searched a lot to find where the problem can be, and tried some tips and alike working examples, but nothing seems to help. Here is my code:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
void paction(int dummy)
{
printf("P*************************************************\n");
}
void caction(int dummy)
{
printf("C*************************************************\n");
}
int main()
{
int pfd[2];
int pfd2[2];
pid_t cfork, pfork;
if (pipe(pfd) == -1 || pipe(pfd2) == -1) {
fprintf(stderr,"Pipe failed");
exit(1);
}
cfork = fork();
signal(SIGUSR1, paction);
if (cfork == -1) {
printf("Fork Failed\n");
exit(1);
}
else if (cfork > 0) { /*parent process*/
int numbers[] = {1, 2,3, 4, 5};
int numbers2[] = { 6, 7,8, 9, 10 };
close(pfd[0]); /*close read end, write and then close write end*/
/*write part*/
int limit = 5;
int i;
for (i = 0; i < limit; i++) {
printf("Parent sends: %d\n", numbers[i]);
write(pfd[1], &numbers[i], sizeof(numbers[i]));
printf("Child sends: %d\n", numbers2[i]);
write(pfd2[1], &numbers2[i], sizeof(numbers2[i]));
}
printf("***************************************************\n");
close(pfd[1]);
close(pfd2[1]);
/*read part/////////////////////////////////////////*/
int temp;
int reads = 5;
int j;
for (j = 0; j < reads; j++) {
sleep(1);
read(pfd2[0], &temp, sizeof(temp));
printf("Parent gets: %d\n", temp);
kill(cfork, SIGUSR1);
pause();
}
/*printf("***************************************************\n");*/
kill( cfork, SIGUSR1 );
close(pfd2[0]);
}
else { /*child process*/
signal(SIGUSR1, caction);
close(pfd[1]);
int temp;
int reads = 5;
int j;
pfork = getppid();
for (j = 0; j < reads; j++) {
sleep(1);
read(pfd[0], &temp, sizeof(temp));
printf("Child gets: %d\n", temp);
kill(getppid(), SIGUSR1);
pause();
}
/*printf("***************************************************\n");*/
close(pfd[0]);
close(pfd2[0]);
}
return 0;
}
My output looks like this:
> Parent sends:1
> Child sends:6
> Parent sends:2
> Child sends:7
> Parent sends:3
> Child sends:8
> Parent sends:4
> Child sends:9
> Parent sends:5
> Child sends:10
> **************************************************************
Parent gets:6
> C************************************************************
> Child gets:1
> P*************************************************************
> Parent gets:7
And here is when it stops.
If someone can help me I would really appreciate it because I really want to know where the problem is, and since I am a beginner in C programming and processes!
Thank you in advance
printf() is not an async-safe function. Calling printf() in both normal code and a signal handler will cause undefined behavior. In particular, printf() may need to take a lock on the output-stream, while taking locks in signal-handlers is very inadvisable (risk of self-deadlock).
Maybe it is a bad idea to use signals, but I had a task in which it was assigned to use SIGUSR1. I solved the issue by adding:
static struct sigaction pact, cact;
/* set SIGUSR1 action for parent */;
pact.sa_handler = p_action;
sigaction(SIGUSR1, &pact, NULL);
After the parent was assigned the first action, it worked fine.
Thank you:)

How to implement pipes for multiple processes?

I am creating multiple processes and I need to create two unnamed pipes for each process.
For each child, one pipe will be used to get int value from parent; one for sending to int arrays to parent. Parent will do some things while getting new data from childs.
The base code:
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // for reaching unix operations
int main(int argc, char *argv[]){
pid_t main = getpid();
int N = 30;
int i;
pid_t* children = (pid_t*) malloc(sizeof(pid_t) * N);
for(i = 0; i < N; i++){
pid_t child = fork();
if ( child == 0){
pid_t me = getpid();
printf("I'm a child and my pid is: %d\n", me);
sleep(1);
// exit(4);
return me * 2;
} else if ( child < 0){
// printf("Could not create child\n");
} else {
children[i] = child;
// printf("I have created a child and its pid %d\n", child);
}
}
// The child never reaches here
for(i = 0; i < N; i++){
int status;
waitpid(children[i], &status, 0);
printf("Process %d exited with return code %d\n", children[i], WEXITSTATUS(status));
}
return 0;
}
I tried many things with no success and I'm lost. Can you help me to continue?
Any help is appreciated! Thank you.
Here's how to set up one pipe for each child process so that each child writes to the parent:
Since you need two file descriptors for each child, declare:
int fd[2 * N];
Initialize them appropriately:
for (int i = 0; i < N; i++) {
pipe(&fd[2*i]);
}
Inside the i-th child process, use:
write(fd[2*i + 1], write_buffer, SIZE)
to write to the parent, and in the parent use:
read(fd[2*i], read_buffer, SIZE)
to read from the i-th child.
To close the pipes:
Inside the i-th child, you can use
close(fd[2*i])
right away, seeing as you're only writing. After you're done writing call
close(fd[2*i + 1])
to close the write end of the pipe.
The situation is parallel in the parent: when reading from the i-th child you can
close(fd[2*i + 1])
right away, since you're not writing, and after you're done reading call
close(fd[2*i])
to close the read end of the pipe.
Since you need two pipes per child process, create two arrays - one containing pipes for the children writing to the parent, and one containing pipes for the parent writing to the children.

Pipes, Forks and Polls in parent-child process

I am working on an assignment where I have to count the number of chars from the command line arguments. The parent is to pass the child one char at a time and the child is to count the number of chars and return the count to the parent so it can print the number of chars. When I run my program it just sits and does nothing. I think my problem is when I get to the stage of passing the count back to the parent and reaping the child. I think my code is fairly solid up until that point and then that is were I get a little fuzzy. Any help would be greatly appreciated.
// Characters from command line arguments are sent to child process
// from parent process one at a time through pipe.
//
// Child process counts number of characters sent through pipe.
//
// Child process returns number of characters counted to parent process.
//
// Parent process prints number of characters counted by child process.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> //for fork and pip
#include <sys/wait.h>
#include <string.h>
int main(int argc, char **argv)
{
pid_t pid;
int comm[2];
int status;
char src;
// set up pipe
if (pipe(comm))
{
printf("Pipe Error!\n");
return -1;
}
// call fork()
pid = fork();
//check if fork failed
if (pid < 0)
{
printf("Fork Error! %d\n", pid);
return -1;
}
if (pid == 0)
{
// -- running in child process --
//close output side of pipe
close(comm[1]);
int nChars = 0;
printf("in child\n");
// Receive characters from parent process via pipe
// one at a time, and count them.
while (read(comm[0], &src, 1))
{
++nChars;
printf("testing child loop = %d\n", nChars);
}
//close input side of pipe
close(comm[0]);
// Return number of characters counted to parent process.
return nChars;
}
else
{
// -- running in parent process --
int nChars = 0;
//close input side of pipe
close(comm[0]);
printf("Assignment 3\n");
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
int i;
for (i = 1; i < argc; ++i) //loop through each argument
{
int j;
for (j = 0; j < strlen(argv[i]); ++j) //loop through each character in argument
write(comm[1], &argv[i][j], 1);
}
//closing the write end of the pipe
close(comm[1]);
// Wait for child process to return. Reap child process.
waitpid(pid, &status, 0);
// Receive number of characters counted via the value
// returned when the child process is reaped
printf("child counted %d chars\n", nChars);
return 0;
}
}
Here is basically how you should have done it - unless you were absolutely forced to go the return code route.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); } while (0)
#define c2p 0
#define p2c 1
#define READEND 0
#define WRITEEND 1
int main(int argc, char **argv)
{
pid_t pid;
int comm[2][2];
char src;
for (int i = 0; i < 2; ++i)
if (pipe(comm[i]))
errExit("pipe");
if ((pid = fork()) == -1)
errExit("fork");
if (! pid)
{
close(comm[p2c][WRITEEND]);
close(comm[c2p][READEND]);
int nChars = 0;
while (read(comm[p2c][READEND], &src, 1))
++nChars;
write(comm[c2p][WRITEEND], &nChars, sizeof(nChars));
close(comm[c2p][WRITEEND]); //sends eof to parent
printf("child counted %d chars\n", nChars);
return 0;
}
int nChars = 0;
close(comm[p2c][READEND]);
close(comm[c2p][WRITEEND]);
printf("Assignment 3\n");
for (int i = 1; i < argc; ++i) //loop through each argument
{
int len = strlen(argv[i]);
for (int j = 0; j < len; ++j)
write(comm[p2c][WRITEEND], &argv[i][j], 1);
}
close(comm[p2c][WRITEEND]); //sends eof to child
read(comm[c2p][READEND], &nChars, sizeof(nChars)); //should really be in a loop - your task
close(comm[c2p][READEND]);
wait(0);
printf("parent reports %d chars\n", nChars);
return 0;
}

Resources