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: %s\n", 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: %s\n", buf);
}
sleep(1);
currentTime = time(NULL);
}
return 0;
}
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.