📄 airline.cpp
字号:
#include <stdio.h>
#include "CMcl.h"
#define NUMBER_AGENTS 10
#define NUMBER_OF_SEATS 40
class SeatDataBase {
private:
// track the status of the seats...
int m_nSeats;
int m_nSeatsAvailable;
BOOL m_bSeatAvailable[NUMBER_OF_SEATS];
// coordinate reader/writer access to the database...
// number of current readers...
int m_nNumberReaders;
// mutex for writers and for modifying m_nNumberReaders
// and m_ceNoReaders...
CMclMutex m_cmNoWriters;
// event which is signaled when there are no readers...
CMclEvent m_ceNoReaders;
public:
SeatDataBase() : m_cmNoWriters(), m_ceNoReaders(TRUE,TRUE) {
m_nNumberReaders = 0;
m_nSeatsAvailable = m_nSeats = NUMBER_OF_SEATS;
for (int i = 0; i < NUMBER_OF_SEATS; i++)
m_bSeatAvailable[i] = TRUE;
};
int NumberOfSeatsAvailable(void) {
return m_nSeatsAvailable;
};
int NumberOfSeats(void) {
return m_nSeats;
};
BOOL CheckSeat( int nSeat) {
if (nSeat > m_nSeats)
return FALSE;
else
return m_bSeatAvailable[nSeat];
};
BOOL ReserveSeat( int nSeat) {
if (nSeat > m_nSeats) {
return FALSE;
}
else if (m_bSeatAvailable[nSeat] == FALSE) {
return FALSE;
}
else {
// simulate that a database update takes some time...
// this will also cause more contention for access to
// the database, which is what we want to simulate...
Sleep(250);
// reserve the seat...
m_bSeatAvailable[nSeat] = FALSE;
m_nSeatsAvailable--;
return TRUE;
}
};
void GrantReaderAccess(void) {
// grab the mutex to modify the state of
// internal objects...
m_cmNoWriters.Wait(INFINITE);
// increase the reader count...
m_nNumberReaders++;
// now there are NOT no readers...
m_ceNoReaders.Reset();
// release the mutex...
m_cmNoWriters.Release();
};
void ReleaseReaderAccess(void) {
// grab the mutex to modify the state of
// internal objects...
m_cmNoWriters.Wait(INFINITE);
// decrease the reader count...
if (--m_nNumberReaders == 0) {
// we must set the no readers event...
m_ceNoReaders.Set();
}
// release the mutex...
m_cmNoWriters.Release();
};
void GrantWriterAccess(void) {
// we must grab BOTH the no readers event and
// the no writers mutex...
m_cmNoWriters.WaitForTwo( m_ceNoReaders, TRUE, INFINITE);
};
void ReleaseWriterAccess(void) {
// now that we are done writing we
// can release the no writers mutex...
m_cmNoWriters.Release();
};
};
class ReservationAgent : public CMclThreadHandler {
private:
int m_nId;
SeatDataBase *m_psdb;
BOOL m_bContinue;
public:
ReservationAgent(int nId, SeatDataBase *psdb) : m_nId(nId), m_psdb( psdb) {
m_bContinue = TRUE;
return;
};
BOOL ReserveSeat(int nSeat) {
m_psdb->GrantWriterAccess();
BOOL bStatus = m_psdb->ReserveSeat(nSeat);
m_psdb->ReleaseWriterAccess();
return bStatus;
};
int FindSeatInFront(int iStartingSeat) {
int nSeat;
m_psdb->GrantReaderAccess();
for (int i = iStartingSeat; i < m_psdb->NumberOfSeats(); i++) {
if (m_psdb->CheckSeat(i) == TRUE) {
nSeat = i;
break;
}
}
if (i == m_psdb->NumberOfSeats())
nSeat = -1;
m_psdb->ReleaseReaderAccess();
return nSeat;
};
int FindSeatInRear(int iStartingSeat) {
int nSeat;
m_psdb->GrantReaderAccess();
for (int i = iStartingSeat; i >= 0; i--) {
if (m_psdb->CheckSeat(i) == TRUE) {
nSeat = i;
break;
}
}
if (i == -1)
nSeat = -1;
m_psdb->ReleaseReaderAccess();
return nSeat;
};
unsigned ThreadHandlerProc(void) {
// intialize random numbers...
srand(GetCurrentThreadId());
printf( "Agent #%d opening ticket counter.\n", m_nId);
while (m_bContinue) {
// customers arrive at random times...
Sleep(rand() % 1000);
BOOL bCustomerSeated = FALSE;
// some customers want a seat in the front, others
// want to sit in the back...
BOOL bPreferFront = rand() & 1;
// seat to start looking at...
int iStartingSeat;
if (bPreferFront)
iStartingSeat = 0;
else
iStartingSeat = m_psdb->NumberOfSeats() - 1;
// work with this customer until they are seated or
// there are no seats left...
while (!bCustomerSeated) {
// are there any seats available? if not the customer
// will be turned away...
if (m_psdb->NumberOfSeatsAvailable() == 0) {
printf( "Agent #%d turned away customer, plane full.\n", m_nId);
// agents will continue to man their counters even when the
// seats are all taken...
break;
}
int nSeat;
if (bPreferFront)
nSeat = FindSeatInFront(iStartingSeat);
else
nSeat = FindSeatInRear(iStartingSeat);
// if the seat number is -1, no seat could be found, the
// plane must have filled up...
if (nSeat == -1) {
printf( "Agent #%d turned away customer, unable to find seat.\n", m_nId);
break;
}
// ask customer if this seat is acceptable...
// since this is a simulation, half of the time
// the customer will not like the seat...
if (rand() & 1) {
printf( "Agent #%d's customer did not like seat #%d, trying again.\n", m_nId, nSeat);
if (bPreferFront)
iStartingSeat++;
else
iStartingSeat--;
}
else {
// we found a seat, try to reserve it...
if (ReserveSeat(nSeat)) {
printf( "Agent #%d reserved seat #%d, %d seats left.\n", m_nId, nSeat, m_psdb->NumberOfSeatsAvailable());
bCustomerSeated = TRUE;
}
else {
// unable to reserve that seat, some other agent must have
// taken it, try again...
printf( "Agent #%d unable to reserve seat #%d, trying again.\n", m_nId, nSeat);
}
}
}
}
printf( "Agent #%d closing ticket counter.\n", m_nId);
return 0;
};
void Stop(void) {
m_bContinue = FALSE;
};
};
class ReservationAgentThread : public CMclThread {
private:
ReservationAgent *m_pAgent;
// internal constructor...
ReservationAgentThread(ReservationAgent *pAgent) : m_pAgent(pAgent), CMclThread(pAgent) {
return;
};
// destructor which cleans up internal thread handler object...
~ReservationAgentThread() {
delete m_pAgent;
};
public:
// users of this class create agents with this static function...
static ReservationAgentThread *CreateReservationAgentThread( int nId, SeatDataBase *psdb) {
ReservationAgent *pAgent = new ReservationAgent(nId, psdb);
return new ReservationAgentThread(pAgent);
};
// stop the agent with this...
void Stop(void) {
m_pAgent->Stop();
};
};
int main(int argc, char *argv[]) {
int i;
// data base for seat reservations...
SeatDataBase sdb;
// ticket agent thread auto pointer array...
CMclDerivedAutoPtr<ReservationAgentThread> apReservationAgentThreads[NUMBER_AGENTS];
// waitable collection to synchronize shutdown...
CMclWaitableCollection collection;
// create the ticket agents and add them to the collection...
for (i = 0; i < NUMBER_AGENTS; i++) {
apReservationAgentThreads[i] = ReservationAgentThread::CreateReservationAgentThread( i, &sdb);
collection.AddObject(*apReservationAgentThreads[i]);
}
// let the simulation run for a while...
Sleep(5000);
// tell the agents to stop selling tickets...
for (i = 0; i < NUMBER_AGENTS; i++) {
apReservationAgentThreads[i]->Stop();
};
// wait for all of the agents to stop...
collection.Wait( TRUE, INFINITE);
// all done...
printf( "All done, exiting.\n");
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -