『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』にある
「Guarded Suspensionパターン」をC++ Builder 2009で実装してみました。
プログラムの意味は『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』をご覧下さい。
C++BuilderにはJavaのsynchronizedがないため、
クリティカルセクション(TCriticalSectionクラス)を使い、
TLockクラスで実装しました。
JavaのwaitメソッドとnotifyAllメソッドの代わりに、
TEventクラスを使って実装してみました。
(ちょっと怪しい)
//スレッドセーフな出力
std::unique_ptr<TCriticalSection> CriticalSection(new TCriticalSection);
void Print(const std::string& S)
{
CriticalSection->Acquire();
std::cout << S << std::endl;
CriticalSection->Release();
}
//Javaのsynchronizedを実現するためのRAII
class TLock
{
public:
TLock(TCriticalSection* CriticalSection): FCriticalSection(CriticalSection)
{
FCriticalSection->Acquire();
};
~TLock()
{
FCriticalSection->Release();
}
private:
TCriticalSection* FCriticalSection;
};
//リクエストを表すクラス
class TRequest
{
public:
TRequest(std::string Name) : FName(Name) {};
std::string GetName() const { return FName; };
std::string ToString() const { return "[ Request " + FName + " ]"; };
private:
const std::string FName;
};
//リクエストを保持しておくクラス
class TRequestQueue
{
public:
TRequestQueue(TEvent* Event)
: FEvent(Event), FCriticalSection(new TCriticalSection) {};
//もっとも古いリクエストを返す。
//リクエストがなければ、他のスレッドがPutRequestするまで待つ。
TRequest GetRequest()
{
TLock(FCriticalSection.get());
while (FQueue.empty())
{
FEvent->WaitFor(1000000);
}
TRequest request = FQueue.front();
FQueue.pop();
return request;
};
//リクエストを追加する
void PutRequest(const TRequest& Request)
{
TLock(FCriticalSection.get());
FQueue.push(Request);
FEvent->SetEvent();
}
private:
std::unique_ptr<TCriticalSection> FCriticalSection;
std::queue<TRequest> FQueue;
TEvent* FEvent;
};
//リクエストを出すクラス
class TClientThread : public TThread
{
public:
__fastcall TClientThread(TRequestQueue* RequestQueue, const std::string& Name)
: TThread(false), FRequestQueue(RequestQueue), FName(Name) {};
protected:
void __fastcall Execute()
{
for (int i = 0; i < 100000; i++)
{
TRequest request((boost::format("No.%d") % i).str());
Print(FName + " requests " + request.ToString());
FRequestQueue->PutRequest(request);
Sleep(random(10000));
}
}
private:
std::string FName;
TRequestQueue* FRequestQueue;
};
//リクエストを受け取るクラス
class TServerThread : public TThread
{
public:
__fastcall TServerThread(TRequestQueue* RequestQueue, const std::string& Name)
: TThread(false), FRequestQueue(RequestQueue), FName(Name) {};
protected:
void __fastcall Execute()
{
for (int i = 0; i < 100000; i++)
{
TRequest request = FRequestQueue->GetRequest();
Print(FName + " handles " + request.ToString());
}
}
private:
std::string FName;
TRequestQueue* FRequestQueue;
};
int _tmain(int argc, _TCHAR* argv[])
{
TEvent* event = new TEvent(NULL, false, false, "", false);
TRequestQueue* requestQueue = new TRequestQueue(event);
TThread* aliceThread = new TClientThread(requestQueue, "Alice");
TThread* bobbyThread = new TServerThread(requestQueue, "Bobby");
aliceThread->WaitFor();
bobbyThread->WaitFor();
return 0;
}