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.
Related
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
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);
}
}
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
I am working on an assignment where we need to use semaphores in order to make the second print of the parent process wait until child executes first. It is first time using semaphores and I certainly understood how they work, however I think I have a problem with the initialising of sem_open().
By following this:
sem_t *sem_open(const char *name, int oflag);
I have created this:
sem_t *sem = sem_open("MYSEM", O_CREAT , 2);
However, when executing my sem_wait are ignored.This is my whole program:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
/* void ChildProcess(void) ChildProcess prototype */
/* void ParentProcess(void) ParentProcess prototype */
int main(int argc, char ** argv){
int pid;
pid = fork();
sem_t *sem = sem_open("MYSEM", O_CREAT , 2);
if (pid<0)
{
printf("Cannot create a child process");
exit(EXIT_FAILURE);
}
else if (pid==0)
{
printf("I am the child process. \n");
printf("The child process is done. \n");
sem_post(sem);
exit(EXIT_SUCCESS);
}
else
{
printf("I am the parent process. \n");
sem_wait(sem);
printf("The parent process is done. \n");
}
sem_destroy(sem);
exit (EXIT_SUCCESS);
}
and what is printing is:
I am the parent process.
The parent process is done.
I am the child process.
The child process is done.
and what should print is this:
I am the parent process.
I am the child process.
The child process is done.
The parent process is done.
in the parent : you create a semaphore, print a message and then wait for the semaphore.
in the child : you create a semaphore, print 2 messages, close the semaphone and exit.
now the parent can return from the wait.
See http://man7.org/linux/man-pages/man3/sem_wait.3.html for a trivial example
The following c program is used to send a message from parent process to the child process(created using fork()) via a pipe and is run on the linux terminal!
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(int argc,char *arg[]){
pid_t child;
int pipefd[2];
int ret;
char message[20];
ret =pipe(pipefd);
if((child=fork())==0){
printf("The child process \n");
close(pipefd[0]);
write(pipefd[1],"Hello from parent",17);
}
else{
close(pipefd[1]);
read(pipefd[0],message,17);
printf("Message from parent %s\n",message);
}
return 0;
}
The above code prints the message "Hello from parent" but at the end of parent part an # sign is printed! what is the reason and how can i rectify it?
Send also null character that is at the end of the string. Same for reading.
write(pipefd[1],"Hello from parent",18);