c parallel processes involving pipe - c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
int i;
int fd[2];
int values[argc - 1];
for( i = 1; i < argc; i++ ) {
pipe(fd);
switch( fork()) {
case 0: /* child */
/* Do stuff */
close(fd[0]);
int value = atoi(argv[i]);
write(fd[1], &value, sizeof(value));
exit( 0 );
case -1:
perror( "fork" );
exit(1);
default: /* parent */
close(fd[1]);
read(fd[0], &values[i - 1], sizeof(values[i - 1]));
/* do stuff, but don't wait() or terminate */
}
}
for (i = 0; i < (argc - 1); i++)
{
printf("%d\n", values[i]);
}
return 0;
}
im trying to create as many processes as the number of arguments given to the executable and have each process pipe the argument to the parent and store into an array and at the end print out the elements of the array. since the processes run in parallel, when i print out the array elements, the order should be random with respect to the order i entered these elements, but that doesnt seem to be the case as i have ran the executable 1 million times, can someone tell me what the problem is? So someone kindly pointed out that read serializes things, what should i do to make the processes truly parallel?

Your pipe read in the parent serializes things.
You (1) create the child; (2) child writes to the pipe; (3) parent will block on read until there is something to read. This repeats for all the children.

Related

Count the number of process created by fork() [duplicate]

How can I display the number of processes created?
(without using a formula)
for (i=0; i<3; i++)
fork();
count = count + 1;
printf("%d",count);
There are a number of ways to do this, and a good technique is to have each child write one byte into a file descriptor which the original process can read. Note that, for the sake of brevity, the following code contains absolutely no error checking. Also, we report only the number of spawned processes (7) rather than counting the original to get a count of 8:
int main(void) {
int fd[2];
int depth = 0; /* keep track of number of generations from original */
int i;
pipe(fd); /* create a pipe which will be inherited by all children */
for(i=0; i<3; i++) {
if(fork() == 0) { /* fork returns 0 in the child */
write(fd[1], &i, 1); /* write one byte into the pipe */
depth += 1;
}
}
close(fd[1]); /* exercise for the reader to learn why this is needed */
if( depth == 0 ) { /* original process */
i=0;
while(read(fd[0],&depth,1) != 0)
i += 1;
printf( "%d total processes spawned", i);
}
return 0;
}
Printing the count value out just once is the easy part. Because you can get the process pid before the for loop. And then get the pid again after the for loop and only print if the pids match. For the counting part, it depends on whether your child processes exit or not. If they exit the solution is easier. The below code demonstrates one possible solution if the child processes exit (for brevity have not done full error checking). The idea is that each child process counts its own children. Parent waits for each child to complete and adds in its count. Haven't had time to fully test/debug the program so there may be some errors. But hopefully gives you the general idea.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t before_pid, after_pid;
pid_t forked_pid;
int count;
int i;
int status;
before_pid = getpid();
count = 1; /* count self */
for (i = 0; i < 3; i++) {
forked_pid = fork();
if (forked_pid > 0) {
waitpid(forked_pid, &status, 0);
/* parent process - count child and descendents */
count += WEXITSTATUS(status);
} else {
/* Child process - init with self count */
count = 1;
}
}
after_pid = getpid();
if (after_pid == before_pid) {
printf("%d processes created\n", count);
}
return (count);
}

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.

Display number of processes in loop with fork

How can I display the number of processes created?
(without using a formula)
for (i=0; i<3; i++)
fork();
count = count + 1;
printf("%d",count);
There are a number of ways to do this, and a good technique is to have each child write one byte into a file descriptor which the original process can read. Note that, for the sake of brevity, the following code contains absolutely no error checking. Also, we report only the number of spawned processes (7) rather than counting the original to get a count of 8:
int main(void) {
int fd[2];
int depth = 0; /* keep track of number of generations from original */
int i;
pipe(fd); /* create a pipe which will be inherited by all children */
for(i=0; i<3; i++) {
if(fork() == 0) { /* fork returns 0 in the child */
write(fd[1], &i, 1); /* write one byte into the pipe */
depth += 1;
}
}
close(fd[1]); /* exercise for the reader to learn why this is needed */
if( depth == 0 ) { /* original process */
i=0;
while(read(fd[0],&depth,1) != 0)
i += 1;
printf( "%d total processes spawned", i);
}
return 0;
}
Printing the count value out just once is the easy part. Because you can get the process pid before the for loop. And then get the pid again after the for loop and only print if the pids match. For the counting part, it depends on whether your child processes exit or not. If they exit the solution is easier. The below code demonstrates one possible solution if the child processes exit (for brevity have not done full error checking). The idea is that each child process counts its own children. Parent waits for each child to complete and adds in its count. Haven't had time to fully test/debug the program so there may be some errors. But hopefully gives you the general idea.
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main(void)
{
pid_t before_pid, after_pid;
pid_t forked_pid;
int count;
int i;
int status;
before_pid = getpid();
count = 1; /* count self */
for (i = 0; i < 3; i++) {
forked_pid = fork();
if (forked_pid > 0) {
waitpid(forked_pid, &status, 0);
/* parent process - count child and descendents */
count += WEXITSTATUS(status);
} else {
/* Child process - init with self count */
count = 1;
}
}
after_pid = getpid();
if (after_pid == before_pid) {
printf("%d processes created\n", count);
}
return (count);
}

Inter-process communication seems to be hanging

This is a program that was designed to take characters from the program call, pipe them one at a time to a child, count them in the child, return that value to the parent and print that value.
For some reason, the number of characters input isn't being displayed. It compiles without error and runs, but doesn't exit properly. This leads me to believe that the parent doesn't successfully reap the child and take the return value from it.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
int main(int argc, char **argv)
{
int comm[2];
char buffer[50];
pid_t pid;
// set up pipe
pipe(comm);
// call fork()
pid = fork();
// code that runs in the child
if (pid == 0) {
// -- running in child process --
int nChars = 0;
close(comm[1]);
// Receive characters from parent process via pipe
// one at a time, and count them.
while(read(comm[0], buffer, 1) ==1) {
++nChars;
}
// Return number of characters counted to parent process.
return nChars;
}
else {
// -- running in parent process --
int nChars = 0;
int size = 0;
printf("CS201 - Assignment 3 - \n");
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
close(comm[0]);
for (int i = 1; i < argc ; i++) {
size = strlen(argv[i]);
for (int j = 0; j < size; j++) {
write(comm[1], &argv[i][j], 1);
}
}
// Wait for child process to return. Reap child process.
// Receive number of characters counted via the value
// returned when the child process is reaped.
wait(&nChars);
printf("child counted %d chars\n", nChars/256);
return 0;
}
}
Your parent process needs to close the pipe after it's done writing.
// Send characters from command line arguments starting with
// argv[1] one at a time through pipe to child process.
close(comm[0]);
for (int i = 1; i < argc ; i++) {
size = strlen(argv[i]);
for (int j = 0; j < size; j++) {
write(comm[1], &argv[i][j], 1);
}
}
close(comm[1]); // <--- add this

parent process, and a child process

I am trying to write a program that The parent process will take the arguments to main() and send the characters in them one at a time to the child process through a pipe (one call to write for each character). The child process will count the characters sent to it by the parent process and print out the number of characters it received from the parent. The child process should not use the arguments to main() in any way whatsoever. The child should return normally and not have the parent kill the child.
Am i counting the arguments right? am i sending the arguments in one at a time, and am i reaping the child?
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#define size = 100;
int main(int argc, char *argv[])
{
int i, count =0;
int c;
int fdest[2]; // for pipe
pid_t pid; //process IDs
char buffer[BUFSIZ];
if (pipe(fdest) < 0) /* attempt to create pipe */
perror( "pipe" );
if ((pid = fork()) < 0) /* attempt to create child / parent process */
{
perror( "fork" );
}
/* parent process */
else if (pid > 0) {
close(fdest[0]);
for (i=1; i < argc; ++i)
{
for (c=0; c < strlen(argv[i]); ++c) {
write(fdest[1], &argv[i][c], 1);
}
}
close(fdest[1]);
wait(NULL);
exit(0);
} else {
/* child Process */
close(fdest[1]);
while (read(fdest[0], &buffer, 1) > 0)
{
count++;
}
printf("\nchild: counted %d characters\n", count);
}
wait(NULL);
exit(0);
}
The second wait() is superfluous; the child has no children of its own to wait for. The second 'exit(0);' could be replaced by 'return(0);'. You could omit the previous 'exit(0);' too.
The '#define size = 100;' is unused, which is just as well since the '=' makes it unusable for most purposes (and the semi-colon is a bad idea too - seldom does a macro end with a semi-colon). It should be '#define size 100' or 'enum { size = 100 };'. Often, people use upper case names for 'manifest constants', hence 'enum { SIZE = 100 };.
If you are reading one character at a time, you really don't need a buffer of size BUFSIZ (which is usually 512 or larger).
Also, it is a bad idea to do 'for (c = 0; c < strlen(argv[c]); c++)' because that calculates the length of the string on each iteration. Replace it with either of these:
for (const char *str = argv[i]; *str != '\0'; str++)
write(fdest, str, 1);
for (c = 0, len = strlen(argv[i]); c < len; c++)
write(fdest[1], &argv[i][c], 1);
You close the unused ends of the pipes - that is a crucial step to making things work correctly.
The code seems to be counting correctly. It works off the shelf when I test it. Why are you suspicious that it does not work?

Resources