使用相同的临界区对象进行读取和写入

发布于 2024-11-14 21:12:19 字数 1145 浏览 5 评论 0原文

我需要编写一个读取和写入文件的类。当我执行写入操作时,不应进行读取,反之亦然。我可以使用单个关键部分对象吗?像这样:

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
}

谢谢。

I need to write a class which reads from and writes to a file. When I do a write operation, read should not take place and also vice versa. Can I use a single critical section object for that? Like this:

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
}

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

星光不落少年眉 2024-11-21 21:12:19

如果您正在谈论相同的文件进行读/写,那么您需要使用相同的关键部分(正如您当前所做的那样),否则一个线程可能正在读取该文件,而另一个线程正在写入该文件,这是正是您使用关键部分要避免的事情。

但是,按照您的 FileWorker 类当前的编写方式,您可以读取/写入任意文件,但具有单个全局临界区。在这种情况下,这仍然有效,但如果很少出现对同一文件的争用,最终会增加额外的开销。这对您来说可能是一个可以接受的权衡,具体取决于您的使用模式以及此代码的时间紧迫性。

此外,正如 Begemoth 指出的那样,如果您创建两个生命周期重叠的 FileWorker,您将会遇到单个全局关键部分的问题。您将需要类似于建议的内容,以确保您不会尝试初始化已初始化的关键部分,或删除已删除的关键部分。

If you're talking about the same file for reading/writing, then you need to use the same critical section (as you have currently done), otherwise one thread could be reading the file, while another thread is writing to it, which is exactly what you are using the critical sections to avoid.

However, the way your FileWorker class is currently written, you can read/write arbitrary files, but have a single global critical section. That still works in this scenario, but it will end up adding extra overhead if there's rarely contention for the same file. This might be an acceptable tradeoff for you, depending on your usage patterns and how time critical this code is.

Also, as Begemoth pointed out, you will have issues with a single global critical section if you create two FileWorkers with overlapping lifetimes. You'll need something similar to what was proposed to make sure you don't try to initialize a critical section that's already been initialized, or delete one that's already been deleted.

正如其他答案所指出的,当同时使用 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

As the other answers have pointed out, a single global critical section leads to problems when using multiple instances of FileWorker at once. You should make the critical section a member of FileWorker, and initialize/delete it in the constructor/destructor.

For the implementation of the locking, I would recommend writing a little helper class to support scoped locking:

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

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

You can use this object like this:

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

To understand how this works, read about RAII.

书间行客 2024-11-21 21:12:19

您需要所有线程使用相同的临界区来保护共享资源。除了构造函数和析构函数之外,代码都可以。此代码会导致未定义的行为:

FileWorker a;
FileWorker b;

因为 g_riticSection 被初始化了两次而没有中间删除。您需要添加静态成员函数来初始化和完成您的类。

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

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

当您需要基于每个文件进行同步时,正确的方法是在文件 I/O 手段(HANDLE、FILE*s、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);
  }
};

此类的实例不可复制且不可分配,这一点很重要,因为必须复制关键部分。

You need to the same critical section by all threads to protect the shared resource. The code is ok except constructor and destructor. This code results to undefined behavior:

FileWorker a;
FileWorker b;

becasuse the g_criticalSection is initialized twice without intermediate deletion. You need to add static member functions to initialize and finalize your class.

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

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

When you need to synchronize on per-file basis the right way is to implement an abstraction on top of you file I/O means (HANDLEs, FILE*s, std::fstream, etc). E.g.

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);
  }
};

Instances of this class are not copyable and not assignable this is important because critical section must be copied.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文