『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』にある
「Balkingパターン」をC++ Builder 2009で実装してみました。
プログラムの意味は『増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編』をご覧下さい。
C++BuilderにはJavaのsynchronizedがないため、
クリティカルセクション(TCriticalSectionクラス)を使い、
TLockクラスで実装しました。
//Javaのsynchronizedを実現するためのRAII
class TLock
{
public:
TLock(TCriticalSection* CriticalSection): FCriticalSection(CriticalSection)
{
FCriticalSection->Acquire();
};
~TLock()
{
FCriticalSection->Release();
}
private:
TCriticalSection* FCriticalSection;
};
//現在のデータを表すクラス
class TData
{
public:
TData(std::string Filename, std::string Content)
: FFilename(Filename), FContent(Content), FChanged(true),
FCriticalSection(new TCriticalSection) {};
//データの内容を書き換える
void Change(std::string NewContent)
{
TLock(FCriticalSection.get());
FContent = NewContent;
FChanged = true;
};
//データの内容が変更されていたらファイルに保存する
void Save(std::string ThreadName)
{
TLock(FCriticalSection.get());
if (!FChanged)
{
return;
}
DoSave(ThreadName);
FChanged = false;
};
private:
const std::string FFilename; //保存するファイルの名前
std::string FContent; //データの内容
bool FChanged; //変更した内容が保存されていないならtrue
std::unique_ptr<TCriticalSection> FCriticalSection;
//データの内容を実際にファイルに保存する
void DoSave(std::string ThreadName)
{
boost::format fmt("%s calls DoSave, content = %s");
std::cout << (fmt % ThreadName % FContent) << std::endl;
//ファイルに保存する処理は省略
}
};
//定期的にデータを保存しようとするクラス
class TSaverThread : public TThread
{
public:
__fastcall TSaverThread(std::string Name, TData* Data)
: TThread(false), FName(Name), FData(Data) {};
protected:
void __fastcall Execute()
{
while (true)
{
FData->Save(FName);
Sleep(1000);
}
}
private:
const std::string FName;
TData* FData;
};
//データを変更・保存するクラス
class TChangerThread : public TThread
{
public:
__fastcall TChangerThread(std::string Name, TData* Data)
: TThread(false), FName(Name), FData(Data) {};
protected:
void __fastcall Execute()
{
boost::format fmt("No. %d");
for (int i = 0; true; i++)
{
FData->Change((fmt % i).str());
Sleep(random(1000)); //仕事のつもり
FData->Save(FName);
}
}
private:
const std::string FName;
TData* FData;
};
int _tmain(int argc, _TCHAR* argv[])
{
TData* data = new TData("data.txt", "(empty)");
new TChangerThread("TChangerThread", data);
new TSaverThread("TSaverThread", data);
Sleep(INFINITE);
return 0;
}