Reputation: 103
Parent process creates N children each one replaces itself with exec. There is a communication between parent and exec through an array of pipes (int pipefd[N][2];)
The exec writes to the pipe with these commands:
char msg[50];
sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
printf("%s\n",msg);
write(i1, msg, strlen(msg)+1);
and the parent reads with these:
for (i=0;i<N;i++) {
close(pipefd[i][1]); // close the write end of the pipe in the parent
read(pipefd[i][0], buffer, sizeof(buffer));
printf("\n-C-\n");
if (buffer[0] == '\t'){
printf("%s\n",buffer);
}
int j;
for (j=0; j<100; j++) {
buffer[j]='\n';
}
close(pipefd[i][0]);
}
Now the problem is that only after the child is terminated the read gets unblocked and prints the buffer. What I want to do is print the buffer immediately after the exec writes to the pipe.
Below is the all the code:
Parent File:
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#define N 5
pid_t *pid;
int pipefd[N][2];
int flag = 0;
int count_ctrl_c = 0;
void signal_handler(int sig){
signal(sig, SIG_IGN);
printf("\n");
flag = 1;
signal(SIGINT, signal_handler);
}
int main(int argc, char *argv[]) {
int i;
for (i = 0; i < N; i++) {
pipe(pipefd[i]);
}
int parent_pid = getpid();
pid= (pid_t *)malloc(N * sizeof(pid_t));
for (i = 0; i < N; i++) {
pid[i] = fork();
if (pid[i] == 0) //The parent process will keep looping
{
char b[50];
sprintf( b, "%d", i+1);
char i0[50];
sprintf( i0, "%d", pipefd[i][0]);
char i1[50];
sprintf( i1, "%d", pipefd[i][1]);
char par_id[50];
sprintf( par_id, "%d", parent_pid);
execl("***the/path/to/exec/calculate***", b,i0,i1,par_id,NULL);
}
}
if (parent_pid == getpid()) {
signal(SIGINT, signal_handler);
while(1){
if (flag){
printf("\n-A-\n");
char buffer[100];
int i;
for (i=0;i<N;i++) {
// Apostellei to shma SIGUSR2 se ola ta paidia tou
kill(pid[i], SIGUSR2);
}
printf("\n-B-\n");
for (i=0;i<N;i++) {
close(pipefd[i][1]); // close the write end of the pipe in the parent
read(pipefd[i][0], buffer, sizeof(buffer));
printf("\n-C-\n");
if (buffer[0] == '\t'){
printf("%s\n",buffer);
}
int j;
for (j=0; j<100; j++) {
buffer[j]='\n';
}
close(pipefd[i][0]);
}
//exit(0);
printf("finished reading\n");
flag = 0;
count_ctrl_c++;
if (count_ctrl_c == 2) {
exit(0);
}
}
}
}
}
calculate.c
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#define N 5
int i0,i1,parent_pid;
int flag = 0;
int time_to_term = 0;
double pi;
void signal_handler2(int sig);
void signal_handler(int sig);
void signal_handler2(int sig){
signal(sig, SIG_IGN);
signal(SIGALRM, SIG_IGN);
flag = 1;
signal(SIGUSR2, signal_handler2);
signal(SIGALRM, signal_handler);
}
void signal_handler(int sig){
signal(sig, SIG_IGN);
pid_t pid = getpid();
printf("time: %d, pid: %d, pi: %1.10f\n", time_to_term, pid, pi);
exit(0);
}
int main(int argc, char *argv[]) {
int pid;
signal(SIGINT, SIG_IGN);
signal(SIGUSR2, signal_handler2);
signal(SIGALRM, signal_handler);
time_to_term = atoi(argv[0]);
alarm(time_to_term);
i0 = atoi(argv[1]);
i1 = atoi(argv[2]);
parent_pid = atoi(argv[3]);
double mul = 1.0;
double par = 2.0;
pi = 3.0;
while(1){
pi = pi + (mul * (4.0 / (par * (par + 1.0) * (par + 2.0))));
mul = mul * (-1.0);
par += 2;
sleep(1);
if (flag) {
signal(SIGALRM, SIG_IGN);
close(i0);
char msg[50];
sprintf( msg, "\tsent from pid: %d, pi= %f", getpid(), pi);
printf("%s\n",msg);
write(i1, msg, strlen(msg)+1);
close(i1);
flag = 0;
signal(SIGALRM, signal_handler);
//exit(0);
}
}
}
Upvotes: 1
Views: 2480
Reputation: 16080
Your operating system is probably buffering the write.
Try using ioctl
and FLUSHW
to explicitly flush the pipe after the call to write
. Also, check your return values in case something insidious is happening. See http://pubs.opengroup.org/onlinepubs/7908799/xsh/ioctl.html for more reading on ioctl
.
Upvotes: 0
Reputation: 6095
IMHO, your design is not really good as all child processes inherit all pipes you created and this is a waste of system resources. The right thing to do would be:
In the parent process:
dup
fd's #0 and #1 to preserve for later use by the parent process; use fcntl
with F_DUPFD_CLOEXEC
on these new fd's to prevent inheritance on exec
close
fd #0
close
fd #1
create a pipe
prevent inheritance of the read fd of the pipe as said above
dup2
write fd of the pipe to make it fd #1; close
the original write fd
fork
& exec
the child process
repeat steps 3 through 7 for all necessary children
dup2
stored duplicates of original fd's #0 and #1 back to #0 and #1 to restore the printf
/scaf
functionality
use select
to poll read fd's of all pipes and possibly #0 if you expect any input on #0
If two-way communication is required then at step 4 create two pipes with appropriate adjustments to the described procedure and repeat steps 2 through 7 to create children.
In the child process (after exec
)
Do all processing as required. Write to the parent either using fd #1 or printf or whatever.
Child process may always obtain its parent PID
with getppid()
Upvotes: 1
Reputation: 1198
General tip for troubleshooting this: Run both sides of the pipeline using the strace
tool (you can use strace -f
to follow forks) so that you can verify what is actually written / read from the pipe.
I suspect that in this case, nothing is written by the child! This is because the stdio layer that you use (printf()) checks whether it is writing to a terminal or to, well, anything else. In case of terminal, it flushes the output after each newline, but in other cases, it flushes only after a large-ish block of data is written (8KiB on GNU systems). Try flushing the output manually using fflush() after printf(). If that helps, you can adjust stdout buffering mode using setvbuf().
Upvotes: 1