Balkingパターン

増補改訂版 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;
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です