This program simulates a variant of Dijkstra’s Producer/Consumer problem. A pipeline is first created followed by a child process using fork(). The child will then write to the pipe a crudely done randomly generated piece of “stock market ticker information”. After waiting for the child/producer process to write this information, the parent/consumer process will read it out.
The first output is correct:
Produced: FPOO 57.83 +0.43 Consumed: FPOO 57.83 +0.43
Any output following this however will always say “Consumed: info from first read“:
Produced: RJII 71.30 -2.71 Consumed: FPOO 57.83 +0.43
I am unsure as to why this would be occurring because my tickerInfo is changing. This is why I suspect I’m reading the pipe incorrectly or perhaps something is improperly structured with my forked processes.
I have compiled the code in g++. It takes an argument as the number of seconds you want the program to run for.
#include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <sys/types.h> #include <unistd.h> #include <time.h> #include <string.h> // generate info for each stock entry void generateTickerInfo(char * info) { int i; int randNum = 0; srand(time(NULL)); // generate seed for random // generate 4 characters for STOCK sym for(i = 0; i < 4; i++) { randNum = rand() % 26 + 65; info[i] = (char)(randNum); } info[4] = ' '; // generate price traded for(i = 5; i < 7; i++) { randNum = rand() % 8 + 1; info[i] = '0' + randNum; } info[7] = '.'; for(i = 8; i < 10; i++) { randNum = rand() % 9; info[i] = '0' + randNum; } info[10] = ' '; // determine if + or - for change amount randNum = rand(); if(randNum % 2 == 1) { info[11] = '+'; } else { info[11] = '-'; } // generate change amount randNum = rand() % 9; info[12] = '0' + randNum; info[13] = '.'; for(i = 14; i < 16; i++) { randNum = rand() % 9; info[i] = '0' + randNum; } } // ** constant and global variables ** const int BUFFER_SIZE = 25; // ** main code ** int main(int argc, char *argv[]) { pid_t cpid; // child process id int myPipe[2]; // [0] read, [1] write char * tickerInfo; // hold current tickerInfo tickerInfo = new char[BUFFER_SIZE]; // info passed through pipe char buf[BUFFER_SIZE]; time_t currentTime, stopTime; // initialize time variables if(argc < 2) { printf("Invalid arg. Type as 'foo.out (# seconds)'"); exit(0); } else { currentTime = time(NULL); stopTime = time(NULL) + (time_t)atoi(argv[1]); } int pipeReturn = pipe(myPipe); if(pipeReturn == -1) { // handle pipe creation error perror("pipe error..."); exit(0); } // main loop; continue until desired time has elapsed while(currentTime < stopTime) { cpid = fork(); if(cpid < 0) { // handle process creation error perror("forking error...n"); exit(0); } else if(cpid == 0) { // child process close(myPipe[0]); // child does not need to read generateTickerInfo(tickerInfo); write(myPipe[1], tickerInfo, BUFFER_SIZE); printf("Produced: %sn", tickerInfo); exit(0); } else if(cpid > 0) { // parent process wait(0); close(myPipe[1]); // parent does not need to write read(myPipe[0], buf, BUFFER_SIZE); printf("Consumed: %sn", buf); } sleep(1); currentTime = time(NULL); } return 0; }
Advertisement
Answer
After the first child is done and you close the write end of the pipe in the parent process, you go back to the top of the loop and create another child. This child doesn’t inherit a write fd. The write fd is gone. The write
in the second child fails, but you didn’t check its return value for error so you don’t notice.
The parent then reads an EOF from the pipe since there are no remaining writers. Since you didn’t check the read
return value either (bad habit you’ve got!) you don’t notice that, and just print the buffer which still contains its previous contents.