[C++Builder] TMultiReadExclusiveWriteSynchronizerでRead-Write Lockパターン

TMultiReadExclusiveWriteSynchronizerを使用すると、保護されたメモリから複数のスレッドが同時に読み出すことを可能とし、かつメモリに書き込むスレッドは排他的にアクセスできます。

TMultiReadExclusiveWriteSynchronizerを使うには、まずグローバルインスタンスを作成します。

std::unique_ptr<TMultiReadExclusiveWriteSynchronizer> ReadWriteLock(new TMultiReadExclusiveWriteSynchronizer());

読み取りを行うスレッドでは、読み込む時はBeginReadメソッド、読み取りが終わったらEndReadメソッドを読み出します。

ReadWriteLock->BeginRead();
//ここで読み取り処理
ReadWriteLock->EndRead();

書き込みを行うスレッドでは、書き込む時はBeginWriteメソッド、書き込みが終わったらEndWriteを読み出します。

ReadWriteLock->BeginWrite();
//ここで書き込み処理
ReadWriteLock->EndWrite();

以前に書いた「Read-Write Lockパターン」もTMultiReadExclusiveWriteSynchronizerを使うと、ずっと簡単に書くことができました。

#include <tchar.h>
#include <iostream>
#include <memory>
#include <string>

//スレッドセーフな出力
std::unique_ptr<TCriticalSection> CriticalSection(new TCriticalSection);
void Print(const std::string& S)
{
  CriticalSection->Acquire();
  std::cout << S << std::endl;
  CriticalSection->Release();
}

//TDataクラス
//ゆっくりと読み書きを行う
class TData
{
public:
  TData(int Count) : FBuffer(std::string(Count, '*')) {}
  std::string Read() {
    Sleep(50);
    return FBuffer;
  };
  void Write(char C) {
    for (std::string::size_type i = 0; i < FBuffer.size(); ++i)
    {
      FBuffer[i] = C;
      Sleep(50);
    }
  }
private:
  std::string FBuffer;
};

//グローバルインスタンスを作成します。
std::unique_ptr<TMultiReadExclusiveWriteSynchronizer> ReadWriteLock(new TMultiReadExclusiveWriteSynchronizer());

//読み出しスレッド
class TReaderThread : public TThread {
public:
  __fastcall TReaderThread(std::string Name, TData* Data) : TThread(false), FName(Name), FData(Data) {}
protected:
  void __fastcall Execute() {
    while (true) {
      ReadWriteLock->BeginRead(); //読み取り前
      std::string readbuf = FData->Read();
      ReadWriteLock->EndRead(); //読み取り終了
      Print(FName + " reads " + readbuf);
    }
  }
private:
  const std::string FName;
  TData* FData;
};
//書き込みスレッド
class TWriterThread : public TThread {
public:
  __fastcall TWriterThread(TData* Data, std::string Filter)
       : TThread(false), FData(Data), FFilter(Filter), FIndex(0) {}
protected:
  void __fastcall Execute() {
    while (true) {
      ReadWriteLock->BeginWrite(); //書き込み前
      FData->Write(NextChar());
      ReadWriteLock->EndWrite(); //書き込み終了
      Sleep(random(3000));
    }
  };
private:
  TData* FData;
  const std::string FFilter;
  unsigned int FIndex;
  char NextChar() {
    char c = FFilter[FIndex];
    FIndex++;
    if (FIndex >= FFilter.size()) FIndex = 0;
    return c;
  };
};
int _tmain(int argc, _TCHAR* argv[])
{
  TData* data = new TData(10);
  new TReaderThread("TReaderThread-1", data);
  new TReaderThread("TReaderThread-2", data);
  new TReaderThread("TReaderThread-3", data);
  new TReaderThread("TReaderThread-4", data);
  new TReaderThread("TReaderThread-5", data);
  new TReaderThread("TReaderThread-6", data);
  new TWriterThread(data, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
  new TWriterThread(data, "abcdefghijklmnopqrstuvwxyz");

  Sleep(INFINITE);
  return 0;
}

コメントを残す

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

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください