4

ファイルの読み取りと書き込みを行うクラスを作成する必要があります。書き込み操作を行うと、読み取りは行われず、その逆も同様です。そのために単一のクリティカル セクション オブジェクトを使用できますか? このような:

FileWorker.h

class FileWorker
{
public:
    FileWorker();
    void WriteIntoFile(const char* fileName, const char* stringToWrite);
    void ReadFromFile(const char* fileName, char* stringToRead, int* stringLength);
    ~FileWorker();
};

FileWorker.cpp

#include <windows.h>
#include "FileWorker.h"

static CRITICAL_SECTION g_criticalSection;

FileWorker::FileWorker()
{
#ifdef WIN32APP
    InitializeCriticalSection(&g_criticalSection);
#endif
}

void FileWorker::ReadFromFile(const char *fileName, char *stringToRead, int *stringLength)
{
    EnterCriticalSection(&g_criticalSection);
    // Do Read
    LeaveCriticalSection(&g_criticalSection);
}

void FileWorker::WriteIntoFile(const char *fileName, const char *stringToWrite)
{
    EnterCriticalSection(&g_criticalSection);
    // Do Write
    LeaveCriticalSection(&g_criticalSection);
}

FileWorker::~FileWorker()
{
#ifdef WIN32APP
    DeleteCriticalSection(&g_criticalSection);
#endif
}

ありがとう。

4

3 に答える 3

3

読み取り/書き込み用に同じファイルについて話している場合は、(現在行っているように) 同じクリティカル セクションを使用する必要があります。クリティカルセクションを使用して回避していることとまったく同じです。

ただし、現在の FileWorker クラスの記述方法では、任意のファイルを読み書きできますが、単一のグローバル クリティカル セクションがあります。これはこのシナリオでも機能しますが、同じファイルの競合がめったにない場合は、余分なオーバーヘッドが追加されることになります。これは、使用パターンとこのコードがどれほどタイム クリティカルであるかによって、許容できるトレードオフになる場合があります。

また、Begemoth が指摘したように、有効期間が重複する 2 つの FileWorker を作成すると、単一のグローバル クリティカル セクションで問題が発生します。既に初期化されているクリティカル セクションを初期化したり、既に削除されているクリティカル セクションを削除したりしないようにするために、提案されたものと同様のものが必要になります。

于 2011-06-09T05:01:29.023 に答える
2

他の回答が指摘しているようにFileWorker、一度に複数のインスタンスを使用すると、単一のグローバル クリティカル セクションが問題を引き起こします。クリティカル セクションを のメンバーにFileWorkerし、コンストラクタ/デストラクタで初期化/削除する必要があります。

ロックの実装については、スコープ付きロックをサポートする小さなヘルパー クラスを作成することをお勧めします。

class ScopedCriticalSection {
public:
    ScopedCriticalSection(CRITICAL_SECTION & criticalSection)
      : m_criticalSection(criticalSection)
    {
        EnterCriticalSection(&m_criticalSection);
    }

    ~ScopedCriticalSection() {
        LeaveCriticalSection(&m_criticalSection);
    }
private:
    CRITICAL_SECTION & m_criticalSection;
}

このオブジェクトは次のように使用できます。

void FileWorker::ReadFromFile(const char *fileName, char *stringToRead, 
                              int *stringLength)
{
    ScopedCriticalSection guard(m_criticalSection); // enters the cs
    // read stuff
} // the critical section is left when the guard is destroyed

これがどのように機能するかを理解するには、RAIIについて読んでください。

于 2011-06-09T07:12:15.563 に答える
0

共有リソースを保護するには、すべてのスレッドで同じクリティカル セクションにする必要があります。コンストラクタとデストラクタ以外のコードは問題ありません。このコードは、未定義の動作を引き起こします。

FileWorker a;
FileWorker b;

g_criticalSection中間の削除なしで 2 回初期化されるためです。クラスを初期化してファイナライズするには、静的メンバー関数を追加する必要があります。

static void FileWorker::initialize()
{
  InitializeCriticalSection(&g_criticalSection);
}

static void FileWorker::finialize()
{
  DeleteCriticalSection(&g_criticalSection);
}

ファイルごとに同期する必要がある場合、正しい方法は、ファイル I/O 手段 (HANDLE、FILE*、std::fstream など) の上に抽象化を実装することです。例えば

class SyncronizedOutStream
{
  CRITICAL_SECTION cs;
  std::ofstream ostm;

  SyncronizedOutStream(const SyncronizedOutStream&);
  void operator= (const SyncronizedOutStream&);
public:
  explicit SyncronizedOutStream(const std::string& filename) 
    : ostm(filename.c_str())
  {
    InitializeCriticalSection(&cs);
  }

  ~SyncronizedOutStream()
  {
    DeleteCriticalSection(&cs);
  }

  template<typename T>
  SyncronizedOutStream& operator<< (T x)
  {
     ostm << x;
     return *this;
  }

  void lock()
  {
    EnterCriticalSection(&cs);
  }

  void release()
  {
    LeaveCriticalSection(&cs);
  }
};

このクラスのインスタンスはコピー可能ではなく、割り当て可能ではありません。クリティカル セクションをコピーする必要があるため、これは重要です。

于 2011-06-09T05:04:08.883 に答える