SOURCE FILE: protocol.cpp
/*
The set-up: two user processes write packets to two protocol
buffers. Each user writes to both buffers. Two agents of
transmission serve the two protocol buffers. Each serves both
buffers.
*/
#include <iostream>
#include <sched.h>
#include <time.h>
#include <pthread.h>
#include <string>
#include "sem.h"
#include "protocol.h"
#include <string>
using namespace std;
/* We need to use this lock to get intelligible printouts
of what the various threads are doing. Warning: Don't
change how this is done until you've thought a WHOLE lot
about the consequences. */
pthread_mutex_t stdoutLock ;
/* Shared var pktBuf is an array of bufferType indexed by
the set {0,1} of protocols. */
bufferType pktBuf[2] ;
/* global variables to represent threads created
dynamically. */
pthread_t user_t[2], agent_t[2] ;
/* Set checking to 1 if you want messages from the
functions below and from sem.cpp, else set to 0. */
int checking ;
/* Use this flag to turn on checking in your main program file. */
int my_checking ;
/* ################################################## */
/* init */
/* ################################################## */
void init()
{
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* (Initialize the flags and semaphores used for
synchronization.) */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* Set checking to 1 if you want messages from the
functions below and from sem.cpp, else set to 0. */
checking = 0 ;
my_checking = 0 ;
if ( 0!=pthread_mutex_init(&stdoutLock, NULL) )
{ cout << "MUTEX INITIALIZATION FAILURE!" << endl ;
exit(-1) ;}
/* initialize random number generator */
srandom(time((time_t *) 0));
}
/* ################################################## */
/* userMessage */
/* ################################################## */
void userMessage (int n, int packetNum, int protocol)
{
pthread_mutex_lock(&stdoutLock) ;
cout << "Copy IN: Packet #" << packetNum
<< " of USER #" << n << " into buffer #" << protocol
<< "." << endl ;
pthread_mutex_unlock(&stdoutLock) ;
}
/* ################################################## */
/* user */
/* ################################################## */
void * user (void * N)
{
int n = (int) N ;
int i, packetNum = 0, protocol, delay ;
do
{
protocol = (random() % 2 ) ;
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* perform synchronization action */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* simulate the writing of a packet
into the buffer */
pktBuf[protocol].info.userID = n ;
pktBuf[protocol].info.packetNum = packetNum ;
delay = random() % 10 ;
/*
if (n==0) delay = random() % 100;
else delay = random() % 1000 ;
*/
for (i=0; i<delay; i++) sched_yield();
userMessage (n, packetNum, protocol) ;
packetNum++ ;
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* perform more synchronization work */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
delay = random() % 10 ;
/*
if (n==0) delay = random() % 100;
else delay = random() % 1000 ;
*/
for (i=0; i<delay; i++) sched_yield();
}
while (1) ;
}
/* ################################################## */
/* agentMessage */
/* ################################################## */
void agentMessage (int n, int packetNum,
int userID, int protocol)
{
pthread_mutex_lock(&stdoutLock) ;
cout << "AGENT #" << n << " copies packet #" << packetNum
<< " of USER #" << userID << " from buffer #" << protocol
<< "." << endl ;
pthread_mutex_unlock(&stdoutLock) ;
}
/* ################################################## */
/* agent */
/* ################################################## */
void * agent (void * N)
{
int n = (int) N ;
int i, packetNum, protocol, userID, delay ;
/* Pick either protocol to start with. */
protocol = (random() % 2 ) ;
do
{
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* Do some synchronization work and if certain conditions
are true then do the block of instructions that follow
*/
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* if (???????) */
{
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* Do some additional work associated with
synchronization */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
packetNum = pktBuf[protocol].info.packetNum ;
userID = pktBuf[protocol].info.userID ;
/* delay = random() % 1000 ; */
delay = random() % 100 ;
/*
if (n==0) delay = random() % 100;
else delay = random() % 1000 ;
*/
for (i=0; i<delay; i++) sched_yield();
agentMessage (n, packetNum, userID, protocol) ;
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* More synchronization code */
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
}
/* else */
{
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
/* This block would get executed instead of the one above
if there was a reason not to let the agent touch the buffer.
This block just does some synchronization tasks. /*
/* ++++++++++++++++++++++++++++++++++++++++++++++++++ */
}
/* Get set to check the other buffer */
protocol = (protocol + 1) % 2 ;
/* delay = random() % 1000 ; */
delay = random() % 100 ;
/*
if (n==0) delay = random() % 100;
else delay = random() % 1000 ;
*/
for (i=0; i<delay; i++) sched_yield();
}
while (1) ;
}
/* ################################################## */
/* main */
/* ################################################## */
main()
{
int thrNum ;
init() ;
for (thrNum=0; thrNum<2; thrNum++)
{
if (0!=pthread_create(&user_t[thrNum], NULL, user, (void *) thrNum ))
{ cout << "THREAD CREATION FAILURE!" << endl ;
exit(-1) ; }
if (0!=pthread_detach(user_t[thrNum]))
{ cout << "THREAD DETACHMENT FAILURE!" << endl ;
exit(-1) ;}
}
if (0!=pthread_create(&agent_t[0], NULL, agent, (void *) 0 ))
{ cout << "THREAD CREATION FAILURE!" << endl ;
exit(-1) ; }
if (0!=pthread_detach(agent_t[0]))
{ cout << "THREAD DETACHMENT FAILURE!" << endl ;
exit(-1) ;}
agent((void *) 1) ;
exit(0) ;
}