⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 airline.cpp

📁 window下的多线程编程参考书。值得一读
💻 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 + -