We have processes STORE_MANAGER, RAND_PROC1, RAND_PROC2 created(forked) by the parent process HMW_MAIN.
STORE_MANAGER receives messages from RAND_PROC1 and RAND_PROC2 through the pipe C_BOX. It responds to messages from RAND_PROC1 by placing the responses in the pipe RAND_BOX1. It responds to messages from RAND_PROC2 by placing the responses in the pipe RAND_BOX2. Each message as it is sent or received, it is time-stamped and logged in the file 'LOG.DAT' by the STORE_MANAGER and by the RAND_PROCi processes.
The STORE_MANAGER keeps in a TABLE TABLE_SIZE [say, 10] pairs (TABLE_ID, TABLE_ELEM). The TABLE will be a structure of the form
struct {
char id[TABLE_ID_SIZE+1];
char value[TABLE_ELEM_SIZE+1];
} TABLE;
not of the form
struct {
char *id;
char *value;
} TABLE;
where TABLE_ID_SIZE and TABLE_ELEM_SIZE are constants, say, 12 and 8.
The ids kept in TABLE are read from the file 'INIT.DAT'.
STORE_MANAGER will initialize the value fields in TABLE with
random strings.
On the TABLE are carried out two operations, TABLE_UPDATE and TABLE_READ.
function TABLE_UPDATE (WHO : TABLE_ID;
WHAT : TABLE_ELEM) return INTEGER;
{It updates the value of WHO to be WHAT. It returns 0 iff successful}
{i.e. if WHO was a TABLE_ID in the table}
{Note that WHO denotes the pair with first element equal to WHO.}
function TABLE_READ (WHO : TABLE_ID;
out WHAT : TABLE_ELEM) return INTEGER;
{It retrieves the value of WHO and stores it in WHAT.
It returns 0 iff successful, i.e. if WHO was a TABLE_ID in the table}
Here is how the STORE_MANAGER should behave:
STORE_MANAGER:
initialization [including opening LOG.DAT in append+write mode,
opening and reading INIT.DAT and initializing TABLE];
loop
wait for the arrival of a new request;
log the message and start the corresponding operation;
end loop
conclusion;
STORE_MANAGER receives messages that consist of, in sequence:
o An Origin Code ['1' for RAND_PROC1, '2' for RAND_PROC2]
o An Origin Id [the process id of the sending process, as a
five digit number]
o A message code ['U' for TABLE_UPDATE, 'R' for TABLE_READ]
o The operands required by the corresponding operation [hence for
TABLE_UPDATE, the 'U' will be followed by a TABLE_ID value [it
is TABLE_ID_SIZE characters]
and by a TABLE_ELEM value [it is TABLE_ELEM_SIZE characters],
while for TABLE_READ, the 'R' will be followed only by TABLE_ID.]
The STORE_MANAGER responses consist of the character representing the operation requested, followed by the result of the operation ['0' for success, '1' for failure], followed by the values involved in the operation [both TABLE_ID and TABLE_ELEM].
RAND_PROC1 and RAND_PROC2 have the same form [but use different seeds for the random number generator]:
RAND_PROCi:
initialization (including opening LOG.DAT in append+write mode,
opening and reading INIT.DAT into a local array IDS];
loop
generate a random TABLE_READ or TABLE_UPDATE request;
[in both operations the TABLE_ID should be selected
at random from IDS; in the TABLE_UPDATE operation
TABLE_ELEM should be created using
a random number generator]
send the request and log it;
wait for the corresponding response and log it;
wait some random time [say, between 0 and 2 seconds];
end loop
conclusion;
In writing RAND_PROCi you should represent the sending of a message
and the receiving of the corresponding response as taking place within
calls to the following functions:
function TABLE_UPDATE (WHO : TABLE_ID;
WHAT : TABLE_ELEM) return INTEGER;
{It updates the value of WHO to be WHAT. It returns 0 iff successful}
{Note that WHO denotes the pair with first element equal to WHO.}
function TABLE_READ (WHO : TABLE_ID;
var WHAT : TABLE_ELEM) return INTEGER;
{It retrieves the value of WHO and stores it in WHAT.
It returns 0 iff successful}
I have used the same name and form for the functions used in
STORE_MANAGER to access TABLE, and in processes RAND_PROC1 and
RAND_PROC2 to communicate with STORE_MANAGER. I did it intentionally to
stress that through communication the TABLE is as if it were local to
its users. [The fact that you are using the same name should not give origin
to problems because they occur in different files and should be
made local to those files.]
HMW_MAIN, after starting the other processes, in a loop prompts the users to ask if they want to see statistical information from RAND_PROC1 and RAND_PROC2.
HMW_MAIN:
pid_t pids[3];
initialization;
if ((pids[0]=fork())<0){perror("Error forking STORE_MANAGER ");exit(1);}
else if (pids[0]==0) STORE_MANAGER();
if ((pids[1]=fork())<0) {perror("Error forking RAND_PROC1"); exit(1);}
else if (pids[1]==0) RAND_PROC1();
if ((pids[2]=fork())<0) {perror("Error forking RAND_PROC2"); exit(1);}
else if (pids[2]==0) RAND_PROC2();
loop
Prompt the User;
If the answer is "1" then
send a signal to RAND_PROC1 [RAND_PROC1
will write to the screen the number of Read and
Update messages that it has executed [different
numbers represents the Reads started and completed,
and the Updates started and completed]].
else if the answer is "2", then
the same is done with RAND_PROC2
else
send signals to RAND_PROC1, RAND_PROC2 and
STORE_MANAGER requesting that they terminate;
wait that they all exit and exit the loop;
end loop
conclusion, including closing LOG.DAT;
RAND_PROC1 and RAND_PROC2 should respond within callbacks to the
signals from HMW_MAIN.
The INIT.DAT file is:
NETSCAPE
LASMO
INTEL
HONDA
MICROSOFT
DISNEY
CHEVRON
BORDERS
FINOVA
HALLWOOD
ingargiola@cis.temple.edu