我正在用C++实现一些文件系统。到目前为止,我使用的是fstream
,但我意识到无法在独占模式下打开它。由于有很多线程我想允许多个读取,并且当在写入模式下打开文件时,我想以独占模式打开文件?
做什么是最好的方法?我认为Boost
提供了一些功能。还有其他的可能吗?我也想看一个简单的例子。如果在C++中不容易/很好,我也可以用C语言编写。如何以独占模式在C++中打开文件
我正在使用Windows。
我正在用C++实现一些文件系统。到目前为止,我使用的是fstream
,但我意识到无法在独占模式下打开它。由于有很多线程我想允许多个读取,并且当在写入模式下打开文件时,我想以独占模式打开文件?
做什么是最好的方法?我认为Boost
提供了一些功能。还有其他的可能吗?我也想看一个简单的例子。如果在C++中不容易/很好,我也可以用C语言编写。如何以独占模式在C++中打开文件
我正在使用Windows。
那么你可以手动防止你打开一个文件,如果它已经被写入模式打开。只需在内部跟踪您在写入模式下打开的文件。
也许你可以散列文件名,并在打开写入权限后将其存储在表中。这将允许快速查找以查看文件是否已被打开。
我不确定它是否是最好的主意,因为我将不得不保留所有打开的文件。 (请注意,如果一个fileA在读取模式下打开,并且某人想要在写入模式下打开它,则需要等到读取模式完成)。 – rank1 2013-04-22 07:38:55
在许多操作系统上,这根本不可能,所以C++ 不支持它。你必须写自己的streambuf
。 如果您担心的唯一平台是Windows,则您可以使用 开放的独占模式。 更可能的,但是,你可能需要使用某种形式的文件 锁定,这是更准确,可在大部分的,如果不是 所有平台(但不包括可移植—您需要使用Windows,fcntl
下LockFileEx
下Unix的)。
在Posix下,您还可以使用pthread_rwlock
。 Butenhof 给出了这样的一个实现采用经典的互斥和 条件变量,这是目前在C++ 11,所以你可以 真正实现便携版(提供的所有 读者和作家都在同一个进程—了POSIX 请求将跨越进程边界工作,但这不是针对C++线程原语的 )。
如何以及为什么要编写自己的streambuf?我认为这会更容易使用这个Windows API,如http://msdn.microsoft.com/en-us/library/windows/desktop/aa365204(v=vs.85).aspx – rank1 2013-04-22 10:12:44
@ SebastianCygert The Windows API需要输出一个'char'缓冲区; 'ostream'接口处理格式和转换为字符串。 'streambuf'类是两者之间的桥梁。 – 2013-04-22 11:11:20
如果你的应用程序只能在Windows上运行,那么win32 API函数“CreateFile()”是你的选择。例如:HANDLE hFile = :: CreateFileW(lpszFileFullPathName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);
例如:HANDLE hFile = :: CreateFileW(lpszFileFullPathName,GENERIC_WRITE,\t FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL); – skyfree 2013-04-22 13:24:38
你想编辑你的答案并在那里添加你的例子。 – 2016-06-01 03:05:01
您可以重命名该文件,使用新名称进行更新,然后重新命名。我已经做到了,但有点沉重。
如果你打算使用boost,那么我建议你使用file_lock类。这意味着你想保留你打开/关闭的文件的文件名,因为fstream不会为你做这些。
他们有两种模式lock()
,你可以使用书面形式(在时间,即只有一个这样的锁,共享锁也可以防止这种锁)和lock_sharable()
,您可以使用阅读(即任意数量的线程能够取得这样的一把锁)。
请注意,您会发现以这种方式管理读写操作最终会变得很复杂。也就是说,如果总是有人阅读,那么可共享的锁定可能永远不会被释放。在这种情况下,排他锁永远不会有机会...
// add the lock in your class
#include <boost/interprocess/sync/file_lock.hpp>
class my_files
{
...
private:
...
boost::file_lock m_lock;
};
现在当你想要访问一个文件时,你可以用某种方式锁定它。如果线程负责执行此操作,则可以为用户添加功能以访问该锁。如果你读的执行和写入功能my_files是主管,你想获得该锁基于堆栈的对象,并解锁你(RAII):
class safe_exclusive_lock
{
public:
safe_exclusive_lock(file_lock & lock)
: m_lock_ref(lock)
{
m_lock_ref.lock();
}
~safe_exclusive_lock()
{
m_lock_ref.unlock();
}
private:
file_lock & m_lock_ref;
};
现在可以安全地锁定该文件(即你
ssize_t my_files::read(char *buf, size_t len)
{
safe_exclusive_lock guard(m_lock);
...your read code here...
return len;
} // <- here we get the unlock()
ssize_t my_files::write(char const *buf, size_t len)
{
safe_exclusive_lock guard(m_lock);
...your write code here...
return len;
} // <- here we get the unlock()
的file_lock使用文件,所以你会希望有每次创建file_lock已经创建了fstream的文件:锁,做的事情,可能会抛出,你总是退出当前的{} - 块)之前解锁。如果fstream的文件可能无法在构造函数来创建的,你可能会想改造m_lock变量的唯一指针:
private:
std::unique_ptr<file_lock> m_lock;
当你引用它,你现在需要一个星号:
safe_exclusive_lock guard(*m_lock);
请注意,为了安全,你应该检查一下指针是否确实分配,如果没有定义,这意味着该文件尚未打开,所以我建议你扔:
if(m_lock)
{
safe_exclusive_lock guard(*m_lock);
...do work here...
}
else
{
throw file_not_open();
}
// here the lock was released so you cannot touch the file anymore
在日E打开,创建锁:
bool open(std::string const & filename)
{
m_stream.open(...);
...make sure it worked...
m_lock.reset(new file_lock(filename));
// TODO: you may want a try/catch around the m_lock and
// close the m_stream if it fails or use a local
// variable and swap() on success...
return true;
}
而且不要忘记释放锁对象在接近:
void close()
{
m_lock.reset();
}
相关[boost interprocess_lock不适用于多个进程](http://stackoverflow.com/questions/6697704/boost-interprocess-file-lock-does-not-work-with-multiple-processes) – 2016-06-01 03:31:56
这种低层次的东西最好是用C实现,用尽可能少的开销可能... – 2013-04-22 06:51:17
@ bash.d胡说,你为什么这么想? C++的重点是提供免费的抽象。我曾把你当作知道这件事的人盯上。 – 2013-04-22 09:08:53
@KonradRudolph我不了解你,但我不知道用C++实现的许多文件系统... – 2013-04-22 09:10:12