使用相同的关键部分对象进行阅读和写作
Reading and writing using same critical section object
我需要编写一个从文件中读取和写入文件的类。当我进行写操作时,不应该进行读操作,反之亦然。我可以使用一个关键部分对象吗?像这样:
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
}
谢谢。
如果你谈论的是同一个文件的读/写,那么你需要使用相同的关键部分(就像你目前所做的那样),否则一个线程可能正在读取该文件,而另一个线程正在向其写入,这正是你使用关键部分要避免的。
但是,按照FileWorker类当前的编写方式,您可以读取/写入任意文件,但只有一个全局关键部分。这在这种情况下仍然有效,但如果很少有对同一文件的争用,最终会增加额外的开销。这对您来说可能是一个可以接受的折衷方案,这取决于您的使用模式以及此代码的时间关键性
此外,正如Begemoth所指出的,如果创建两个使用寿命重叠的FileWorker,那么单个全局关键部分就会出现问题。您将需要类似于建议的内容,以确保您不会尝试初始化已初始化的关键部分,或删除已删除的关键部分。
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。
您需要所有线程使用相同的关键部分来保护共享资源。除了构造函数和析构函数外,代码都可以。此代码导致未定义的行为:
FileWorker a;
FileWorker b;
因为CCD_ 5被初始化两次而没有中间删除。您需要添加静态成员函数来初始化和完成类。
static void FileWorker::initialize()
{
InitializeCriticalSection(&g_criticalSection);
}
static void FileWorker::finialize()
{
DeleteCriticalSection(&g_criticalSection);
}
当您需要在每个文件的基础上进行同步时,正确的方法是在文件I/O手段(HANDLEs、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);
}
};
此类的实例不可复制,也不可赋值,这一点很重要,因为必须复制关键节。
相关文章:
- 打印对象的映射,其中另一个对象作为键
- C++中同一基础对象的多个键
- 当覆盖映射中的复杂对象键时,旧对象将被删除(C++)
- C++将键映射到对象
- 迭代 Napi::对象属性(键)在 Node.js C++ N-API 中
- 读取数组中每个对象的所有键值对
- 用unordered_map映射对象作为键
- 通过其char键对对象指针的C 向量进行排序
- 是否可以保证输入<Type>实数时复杂对象的虚部设置为零?
- 在 c++ 中以对象作为键访问值
- 作为映射键的对象在CPP中变为const
- C++:对象键的多映射自定义比较器
- 使用 protobuf 对象作为 std::map 中的键
- 对象来映射键和值
- 使用键旋转对象
- 在向量上迭代,并添加迭代器实际指向的对象作为映射中的键
- 如何使用卡萨布兰卡在现有的web::json::value对象中附加新的键值对?
- 为什么在使用对象作为多映射中的键时,驱动器被称为远远不够
- 映射与对象键,查找和比较功能
- V8如何获取作为参数提供的对象键值