(Latest Revision: 11/13/2005)
PROTOCOL.CPP
/*
This is my solution to the problem!! The catch is that I have removed all the
code that does the synchronization. You can actually compile this, run it,
and watch the fun as all the threads get in each other's way. Just make a
directory containing protocol.strip.cpp, protocol.strip.h, sem.cpp, and sem.h.
Then compile on a Sun Ultra with the command:
g++ protocol.strip.cpp sem.cpp -lpthread -lposix4
In theory, you could write your solution to the problem by just putting
synchronization code in to the "blanks" I left. I don't know if that's a very
good idea. Anyway if you read the code maybe it will help you get a good grasp
of where the problem lies. At the very least you can use parts of it to save
time. For example you could use my functions that write the user and agent
messages.
*/
/*
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) ;
}