我需要编写一个读写文件的类。当我进行写操作时,不应该进行读取,反之亦然。我可以使用单个关键部分对象吗?像这样:
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
}
感谢。
答案 0 :(得分:3)
如果您正在谈论相同的文件进行读/写,那么您需要使用相同的关键部分(就像您目前所做的那样),否则一个线程可能正在读取该文件,而另一个线程正在写对它来说,这正是你使用关键部分要避免的。
但是,当前编写FileWorker类的方式,您可以读/写任意文件,但只有一个全局关键部分。这仍然适用于这种情况,但如果很少争用同一个文件,它最终会增加额外的开销。根据您的使用模式以及此代码的时间关键程度,这可能是您可以接受的权衡。
此外,正如Begemoth所指出的,如果您创建两个具有重叠生命周期的FileWorkers,那么您将遇到单个全局关键部分的问题。您需要与提议的内容类似的内容,以确保您不会尝试初始化已经初始化的关键部分,或者删除已经删除的部分。
答案 1 :(得分:3)
正如其他答案所指出的,当同时使用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。
答案 2 :(得分:0)
所有线程都需要相同的关键部分来保护共享资源。除了构造函数和析构函数之外,代码是可以的。此代码导致未定义的行为:
FileWorker a;
FileWorker b;
因为g_criticalSection
被初始化两次而没有中间删除。您需要添加静态成员函数来初始化和完成您的类。
static void FileWorker::initialize()
{
InitializeCriticalSection(&g_criticalSection);
}
static void FileWorker::finialize()
{
DeleteCriticalSection(&g_criticalSection);
}
当你需要在每个文件的基础上进行同步时,正确的方法是在你的文件I / O手段(HANDLEs,FILE * s,std :: fstream等)之上实现抽象。 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);
}
};
此类的实例不可复制且不可分配这很重要,因为必须复制关键部分。