Why does this function produce so many child processes? - c

I wrote this code in order to calculate the factorial of a number using processes and pipe(). I wanted to pass on the result from the child process to the child process. For example, to create calculate 5! the main which is the father sends the number 1 in the pipe. Then the first child is created and does 1*2, then it pushes in the pipe the number 2, the second child does 2*3 pushes the result in the pipe etc... Also, I use argv[1][0] thinking that we run the program like this (./ex3 5) where 5 is the number of which the factorial we would like to find. After running the program though, I noticed that a lot of child process was created (I only wanted 4). Why is that?
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int fd[2];
int w,count=2;
void child_creator(){
pid_t child;
child=fork();
if (child==0) {
close(fd[1]);
read(fd[0],&w,sizeof(w));
close(fd[0]);
w=w*count;
count++;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
close(fd[0]);
write(fd[1],&w,sizeof(w));
close(fd[1]);
}
}
int main(int argc , char **argv){
int fact=argv[1][0]-'0';
pipe(fd);
w=1;
for (int i=0; i<fact-1; i++){
printf("this is i %d\n", i);
child_creator();
}
return 0;
}
After a suggested answer I tried this code:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
int fd[1000][2];
int w,count=1,j=0;
void child_creator(){
pid_t child;
j++;
pipe(fd[j]);
child=fork();
if (child==0) {
close(fd[j-1][1]);
read(fd[j-1][0],&w,sizeof(w));
close(fd[j-1][0]);
w=w*count;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
close(fd[j-1][0]);
write(fd[j][1],&w,sizeof(w));
close(fd[j][1]);
exit(0);
}
}
int main(int argc , char **argv){
int fact=argv[1][0]-'0';
w=1;
for (int i=0; i<fact-1; i++){
count++;
child_creator();
sleep(2);
}
return 0;
}

Both the parent and child are returning to the for loop in main(). Since the child doesn't need to do anything after it writes its result, it should just exit rather than returning.
You also have problems with your handling of the pipe file descriptors. You do close(fd[1]) at the beginning of the child, but later try to write(fd[1],&w,sizeof(w)). You can't write to a closed FD. You don't need to close anything until the child is exiting, and exiting a process automatically closes all its files.
void child_creator(){
pid_t child;
child=fork();
if (child==0) {
read(fd[0],&w,sizeof(w));
w=w*count;
count++;
printf("I am child %d , my father is %d , the prod is %d\n",getpid(),getppid(),w);
sleep(1);
write(fd[1],&w,sizeof(w));
exit(0);
}
}

Related

C communicate parent and child to increase and print counter

I am trying to write a program so that the parent and child process can communicate back and forth between each other. The parent process and the child process ought to print the values from 1-100 where each process prints the value incrementing it by 1 each time. Now the issue I face is that, I know nothing much about pipes. What I gather from reading materials online is that I can use a pipe to read and write values. I have leveraged this to print something in the child process, and send back something to the parent. Now, I am not sure how to get the parent to return to the child after printing for itself? I know my code is probably all wrong, but I am really not sure what I should do.
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, const char * argv[]) {
int fd[2];
if (pipe(fd)== -1){
printf("An error occured while opening the pipe\n");
}
int id = fork();
int i = 0;
if (id == 0){
close(fd[0]);
printf("In child: %d", i);
i ++;
write(fd[1], &i, sizeof(int));
close(fd[1]);
} else {
wait(NULL);
close(fd[1]);
int y;
read(fd[0],&y, sizeof(int));
close(fd[0]);
}
}
To keep it simple, it's up to you to check return values and handle errors. This will only do it between 0 - 9 and you will have to expand the mathematics.
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pipefd_1[2];
int pipefd_2[2];
pid_t cpid;
pipe(pipefd_1);
pipe(pipefd_2);
cpid = fork();
if (cpid == 0) { /* Child reads from pipe 1, writes to pipe 2*/
char cval[] = {'0'};
close(pipefd_1[1]); /* Close unused write and read ends */
close(pipefd_2[0]);
while (atoi(cval) != 9) {
read(pipefd_1[0], cval, 1);
printf("Child print %d\n", atoi(cval));
cval[0] += 1;
write(pipefd_2[1], cval, 1);
}
} else {
char cval[] = {'0'}; /* Parent writes buf to pipe 1 */
close(pipefd_1[0]); /* Close unused read end */
close(pipefd_2[1]);
while (atoi(cval) != 9) {
write(pipefd_1[1], cval, 1);
read(pipefd_2[0], cval, 1);
printf("Parent print %d\n", atoi(cval));
cval[0] += 1;
}
}
}
Output

Fork and exec several children in linux

I want to fork and exec several processes from another.
My parent code is
/*Daddy.c*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
int status;
char *nChild;
for (int i=0; i<3;i++){
int pid = fork();
if (pid == 0)
{
sprintf(nChild, "%d", i);
printf("%d\n", i);
char *const arguments[]={nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
wait(&status);
printf("Dad %d went out!\n", getpid());
exit(0);
}
and my child process is
/*child.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int args, char **argv){
if( args !=2){
printf("Child going away!\n");
exit(1);
}
printf("Child %s: %d going away stylishly!\n", argv[1], getpid());
exit(0);
}
When I don´t create three forks, but one, I know how to create the child, do some work and exit from child and parent. But, in this case, with several children it seems like the child never executes.
Because of the line wait(&status) I did hope that when the first child exits, the parent also exits but, any child prints any message.
Some relevant previous questions didn´t help.
You need to make parent wait for all child processes to finish. If not, assume that 1 child waited for is done and then parent exits. What about the other 2 children? They become orphan since their parent doesn't wait for them.
pid_t wpid;
int status = 0;
.
.
while ((wpid = wait(&status)) > 0); // the parent waits for all the child processes
This code did the job
/* daddy.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status=0;
char nChild[16];
pid_t wpid;
for (int i=0; i<3;i++){
sprintf(nChild, "%d", i);
int pid = fork();
if (pid == 0)
{
printf("%s\n", nChild);
char *const arguments[]={"child", nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
while ((wpid=wait(&status)) >0);
printf("Dad %d went out!\n", getpid());
exit(0);
}
As #OnzOg said in the comments of the question, allocation of nChild was the main problem. Also execv need pass child name twice, one as argument.
And finally, to improve the code, parent process needs to wait all processes to finish.

write() and read() binary numbers with processes

I am doing this homework for some time and it's giving me a headache.
Write a program that writes the integer “i+1” into element “i” of a table of MAXBUF
integers (for every element of the table). MAXBUF should be initially “#define”d as 10 in the source
code of the program. Then, using only one write() operation, the program should write the entire
table of integers in binary format into an initially truncated file, named “filetable.bin”. In the next
step the program should create a child process, and then print the message “The parent process
is terminating.”, and then exit. The child process should separately read, in binary format, from
the file each integer in the same order as the integers are stored in the file, and print each such
integer to the standard output. In the final step of the program, the child process should wait for its
parent process to terminate, and then print to the standard output the message “The child process
is terminating.”, and then terminate. All the operations on the “filetable.bin” file should be
performed using system calls.
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#define MAXBUF 10
int decimalToBinary(int n);
int main(int argc, char *argv []) {
int i, fd, n, status, childpid;
char buffer[MAXBUF];
pid_t pid = (long)getpid();
fd = open("filetable.bin", O_CREAT | O_RDWR);
for(i=0; i<MAXBUF; i++) {
n=i+1;
buffer[i] = decimalToBinary(n);
}
write(fd,buffer,sizeof(buffer));
childpid = fork();
if(childpid >0) {
printf("The parent process terminating.\n");
exit(0); // or kill(pid, SIGKILL)
}
if(childpid < 0) {
perror("Failed to fork\n");
}
else {
read(fd,&childpid,sizeof(childpid));
write(STDOUT_FILENO,&childpid,sizeof(childpid));
wait(&status);
printf("The child process is terminating\n");
exit(1);
}
return(0);
}
int decimalToBinary(int n) {
int remainder, binary=0, i=1;
while(n!=0) {
remainder = n%2;
n = n/2;
binary = binary + (remainder*i);
i = i*10;
}
return binary;
}
My problem is how do I read from the childpid and write with it in STDOUT?
EDIT: It appears in the output: "The parent process is terminating\n" "The child process is terminating\n". It's missing the STDOUT

Create a chain of n sub processes

In c++ create chain of n processes with n as input and the output of processes should be as parent1->child1(parent2)-->child2(parent3),by using recursive function im able to generate the output but unable to exit the loop i also need help in sending an input of n for which the loop should break.
below is my code:
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int foo(const char *whoami) {
printf("I am a %s. My pid is:%d my ppid is %d\n", whoami, getpid(), getppid() );
return 1;
}
int func() {
pid_t pid=fork();
if (pid==0) { /* only execute this if child */
foo("child");
pid_t pid=fork();
if (pid==0) { /* only execute this if child */
foo("child");
func();
exit(0);
}
}
exit(0);
}
wait(0); /* only the parent waits */
return 0;
}
int main(void){
foo("parent");
func();
return 0;
}
You can't exit the loop for a simple reason, and that is, you spawn child processes endless. Whenever you fork() a new process starts, then it forks again.
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int n=5;
int foo(const char *whoami) {
printf("I am a %s. My pid is:%d my ppid is %d\n", whoami, getpid(), getppid() );
return 1;
}
int func(int n)
{
if (n == 0)
{
return 0;
}
int pid = fork();
if (pid == -1) {
exit(0);
}
if (pid==0) {
foo("child");
n = n-1;
func(n);
exit(0);
}
else {
wait(NULL);
}
return 0;
}
int main()
{
func(n);
return 0;
}
gcc -std=c99 prog.c -o prog
./prog
OUTPUT:
I am a child. My pid is: 1159 my ppid is 1158
I am a child. My pid is: 1160 my ppid is 1159
I am a child. My pid is: 1161 my ppid is 1160
I am a child. My pid is: 1162 my ppid is 1161
I am a child. My pid is: 1163 my ppid is 1162
From what you are saying i understand you are having the following problems:
1st. You are trying to send 'data' from one process to another
2nd. You are trying to find a way to stop your program from running.
Now for the first. If you want to do that and i understood it correctly, there are 2 ways to achieve that. One is the use of shared memory and the other is the use of pipelines. Shared memory is pretty obvious on what is doing. Pipes are taking the stdout of a process and redirecting it as a stdin in the next process.
Now you need a closure to your program. A child process is executed when it executes a command(exec) or when it is told so(with an IF statement for example and a return). You can create a statement of your liking, and when a child process meets your requirments then you can make it die(There is also a way to kill the parent process from the child process with the kill(pid, SIGKILL); command.
I didn't provide you with any code because it is unclear to me the exact nature of your problem.
Hope my assuming led you to something!

Cant read messages from processes using multiple pipes in c

Im creating pipes for multiple children. The code catches a signal fro the keyboard and then the child should sent a message to the father with its result. The handling of the signal works fine but i cant sent the result to the father. I am i doing something wrong here?
The code of the father process is :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
pid_t *childs; //array for storing childs pids
int number_of_childs;//variable for the number of childs
int exit_count=0;
int *fd;
/*Handler for the SIGINT signal*/
void control_handler(int sig)
{
if (sig==SIGINT){
int j,bytes;
char message[512];
/*Sending SIGUSR1*/
for (j=0;j<number_of_childs;j++)
{
kill(childs[j],SIGUSR1);
}
/*Reading from PIPES*/
for (j=0;j<number_of_childs;j++)
{
close(fd[(2*j)+1]);
bytes = read(fd[(2*j)], message, sizeof(message));
printf("Read from: %s\n",message);
close(fd[2*j]);
}
}
if (sig==SIGUSR2)
{
exit_count++;
}
}
main (int argc,char *argv[]){
int i,child_status;
char cast[512];
char cast2[512];
char cast3[512];
int pid;
number_of_childs=atoi(argv[1]);
signal(SIGINT,control_handler);
signal(SIGUSR2,control_handler);
/*Creating array for children pipes*/
fd=(int*)malloc((2*number_of_childs)*sizeof(int));
/*array that holds the pids for every child used in sending signals*/
childs=malloc(number_of_childs*sizeof (pid_t));
for (i=0;i<number_of_childs;i++){
pid=fork();
/*Create pipes to communicate with all children*/
if(pipe(fd+(2*i))==-1)
{
perror("pipe");exit(1);
}
/*Fathers code goes here*/
if(pid!=0)
{
printf("Parent process: PID= %d,PPID=%d, CPID=%d \n",getpid(),getppid(),pid);
childs[i]=pid; // Keep all your childs in an array
printf("Child:%d\n",childs[i]);
}
/*If you are a child*/
else
{
/*Change the code for the childs and set the time of execution*/
sprintf(cast,"%d",i+1); // make the time char
sprintf(cast2,"%d",(2*i)+1); //make the pipe char
sprintf(cast3,"%d",number_of_childs);
execl("./Child.out","",cast,cast2,cast3,NULL);
}
}
/*Father should never terminate*/
while (exit_count!=number_of_childs);
printf("Father pospastex!!\n");
}
the code for the child children is :
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <string.h>
#define WRITE 0
#define READ 1
/*Global declerations*/
int alarmflag=0;
double result=0;
int count=0;
int global_pipe;
int *fd;
/*Handler for the alarm and SIGUSR1 signal*/
void signal_handler (int sig)
{
if(sig==SIGALRM)
{
printf("Im child with pid:%d im going to die my value is %lf \n",getpid(),result);
alarmflag=1;
}
if(sig==SIGUSR1)
{
count++;
char message[512];
if(count==1)
{
close(fd[global_pipe-1]);
sprintf(message,"%d,%lf",getpid(),result);
write(fd[global_pipe],message,strlen(message)+1);
close(fd[global_pipe]);
//printf("PID:%d report: %lf\n",getpid(),result);
}
if(count==2)
{
close(fd[global_pipe-1]);
sprintf(message,"%d,%lf",getpid(),result);
write(fd[global_pipe],message,strlen(message)+1);
close(fd[global_pipe]);
//printf("PID:%d report2 : %lf\n",getpid(),result);
//kill(getppid(),SIGUSR2);
//exit(0);
}
}
if(sig==SIGINT)
{
/*Do nothing*/
}
}
double p_calculation ()
{
int i=2;
result=3;
double prosimo=-1;
while(!alarmflag)
{
prosimo=prosimo*(-1);
result=result+(prosimo*(4/((double)i*((double)i+1)*((double)i+2))));
i=i+2;
}
}
main(int argc,char *argv[])
{
int pipe;
int size_fd;
size_fd=(atoi(argv[3]));
pipe=(atoi(argv[2]));
global_pipe=pipe;
fd=(int*)malloc(size_fd*sizeof(int));
/*handling signals*/
signal(SIGALRM,signal_handler);
signal(SIGUSR1,signal_handler);
signal(SIGINT,signal_handler);
/*Notify for execution time*/
printf("PID : %d with PPID : %d executing for %d seconds \n",getpid(),getppid(),atoi(argv[1]));
//printf("pipe:%d\n",pipe);
/*end this after the value passed as argument*/
alarm(atoi(argv[1]));
p_calculation();
/*Notify for finish*/
printf("Done!!!\n");
}
There are a number of problems related to your pipes:
you call pipe AFTER you call fork, so you end up with two independent pipes (one in the child and one in the parent). The parent listens to the one it creates (and noone is writing to), so it never sees anything.
you pass the index in your global fd array to the child rather than the file descriptor of the pipe. The child has its own global fd array that contains random garbage, so you are essentially writing to a random file descriptor rather than the pipe.
you don't close the unneeded pipe ends in the various processes they exist in, so you cna never reliably get EOFs
If you search for pipe+child here on stackoverflow, you'll see a large number of questions with example code trying to do things similar to what you are doing -- you may find it useful to read through those questions and answers.

Resources