#include #include #include #include "Semaphore.h" #include "Thread.h" using namespace std; // 「仕事」一つ分の表す class CJob { public: int JobData; }; // 「仕事」のリストを保持・入出力を行う class CJobList { public: CJobList() : semaList( 1 ), semaWait( 0 ), semaExitFlg( 1 ), ExitFlg( false ) {}; // リストに仕事を追加する void push( const CJob &r ) { // リストに対して排他制御を掛ける semaList.P(); // リストに追加する listJob.push_back( r ); // listJobに追加された分、semaWaitを加算する semaWait.V(); // 排他制御を解除する semaList.V(); }; // リストから仕事を取り出す bool pop( CJob *pJob ) { int flg; // listJobにデータが追加されるまで待ち合わせる semaWait.P(); // ExitFlgに対する排他制御を掛ける semaExitFlg.P(); // 終了フラグの値を取得する // 変数flgはスレッドローカルであることに注意 flg = ExitFlg; // ExitFlgに対する排他制御を解除する semaExitFlg.V(); if ( flg ) { // 割り込みが掛けられている // semaWaitで待っている他のスレッドが動けるようにしてやる semaWait.V(); return false; } // リストに対して排他制御を掛ける semaList.P(); // リストから仕事を取り出す (*pJob) = *( listJob.begin() ); listJob.erase( listJob.begin() ); // 排他制御を解除する semaList.V(); return true; }; // 割り込み void Interrupt() { // ExitFlgに対する排他制御を掛ける semaExitFlg.P(); // 終了フラグを設定する ExitFlg = true; // semaWaitで待ち合わせているスレッドを走らせてやる semaWait.V(); // ExitFlgに対する排他制御を解除する semaExitFlg.V(); }; protected: // 「仕事」のリスト list< CJob > listJob; // listJobにアクセスを行うための排他制御用 CSemaphore semaList; // listJobにデータが来るまでの待ち合わせ用 CSemaphore semaWait; // 終了フラグ bool ExitFlg; // ExitFlgに対する排他制御用 CSemaphore semaExitFlg; }; // 生産者 class CProducer : public CThread { public: CProducer( CJobList *p ) : pJobList( p ), ExitFlg( false ) {} void run() { CJob job; int i = 0; while ( !ExitFlg ) { // 仕事を生産する job.JobData = i; i++; // リストに追加する pJobList->push( job ); } }; void Interrupt() { ExitFlg = true; }; protected: CJobList *pJobList; bool ExitFlg; }; // 消費者 class CCustomer : public CThread { public: CCustomer( CJobList *pJ, CSemaphore *pS ) : pJobList( pJ ), pSemaStdout( pS ) {} void run() { CJob job; int i; while ( -1 ) { // 仕事を取り出す if ( !pJobList->pop( &job ) ) return; // 仕事をする pSemaStdout->P(); printf( "Customer = 0x%08X : JobData = %d\n", this, job.JobData ); pSemaStdout->V(); } }; protected: CJobList *pJobList; CSemaphore *pSemaStdout; // 標準出力の排他制御用 }; int main() { CProducer *pProducer; // 生産者 CCustomer *pvCustomer[10]; // 消費者 CJobList JobList; // 仕事のリスト CSemaphore semaStdout( 1 ); // 標準出力の排他制御用 int i; // 生産者および消費者を生成 pProducer = new CProducer( &JobList ); for ( i = 0; i < 10; i++ ) { pvCustomer[i] = new CCustomer( &JobList, &semaStdout ); } // 生産者と消費者のスレッドを生成する pProducer->start(); for ( i = 0; i < 10; i++ ) { pvCustomer[i]->start(); } // 2秒ほど待ち合わせる sleep( 2 ); // 生産者と消費者のスレッドに中断を通知する pProducer->Interrupt(); JobList.Interrupt(); // 生産者と消費者のスレッドが終了するのを待ち合わせる pProducer->Wait(); for ( i = 0; i < 10; i++ ) { pvCustomer[i]->Wait(); } // 生産者と消費者のオブジェクトを破棄する delete pProducer; pProducer = NULL; for ( i = 0; i < 10; i++ ) { delete pvCustomer[i]; pvCustomer[i] = NULL; } return 0; }