2013-04-22 731 views
3

我正在用C++实现一些文件系统。到目前为止,我使用的是fstream,但我意识到无法在独占模式下打开它。由于有很多线程我想允许多个读取,并且当在写入模式下打开文件时,我想以独占模式打开文件?
做什么是最好的方法?我认为Boost提供了一些功能。还有其他的可能吗?我也想看一个简单的例子。如果在C++中不容易/很好,我也可以用C语言编写。如何以独占模式在C++中打开文件

我正在使用Windows。

+1

这种低层次的东西最好是用C实现,用尽可能少的开销可能... – 2013-04-22 06:51:17

+1

@ bash.d胡说,你为什么这么想? C++的重点是提供免费的抽象。我曾把你当作知道这件事的人盯上。 – 2013-04-22 09:08:53

+1

@KonradRudolph我不了解你,但我不知道用C++实现的许多文件系统... – 2013-04-22 09:10:12

回答

0

那么你可以手动防止你打开一个文件,如果它已经被写入模式打开。只需在内部跟踪您在写入模式下打开的文件。

也许你可以散列文件名,并在打开写入权限后将其存储在表中。这将允许快速查找以查看文件是否已被打开。

+0

我不确定它是否是最好的主意,因为我将不得不保留所有打开的文件。 (请注意,如果一个fileA在读取模式下打开,并且某人想要在写入模式下打开它,则需要等到读取模式完成)。 – rank1 2013-04-22 07:38:55

2

在许多操作系统上,这根本不可能,所以C++ 不支持它。你必须写自己的streambuf。 如果您担心的唯一平台是Windows,则您可以使用 开放的独占模式。 更可能的,但是,你可能需要使用某种形式的文件 锁定,这是更准确,可在大部分的,如果不是 所有平台(但不包括可移植—您需要使用Windows,fcntlLockFileEx 下Unix的)。

在Posix下,您还可以使用pthread_rwlock。 Butenhof 给出了这样的一个实现采用经典的互斥和 条件变量,这是目前在C++ 11,所以你可以 真正实现便携版(提供的所有 读者和作家都在同一个进程—了POSIX 请求将跨越进程边界工作,但这不是针对C++线程原语的 )。

+0

如何以及为什么要编写自己的streambuf?我认为这会更容易使用这个Windows API,如http://msdn.microsoft.com/en-us/library/windows/desktop/aa365204(v=vs.85).aspx – rank1 2013-04-22 10:12:44

+0

@ SebastianCygert The Windows API需要输出一个'char'缓冲区; 'ostream'接口处理格式和转换为字符串。 'streambuf'类是两者之间的桥梁。 – 2013-04-22 11:11:20

1

如果你的应用程序只能在Windows上运行,那么win32 API函数“CreateFile()”是你的选择。例如:HANDLE hFile = :: CreateFileW(lpszFileFullPathName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL);

+0

例如:HANDLE hFile = :: CreateFileW(lpszFileFullPathName,GENERIC_WRITE,\t FILE_SHARE_READ,NULL,OPEN_EXISTING,NULL,NULL); – skyfree 2013-04-22 13:24:38

+0

你想编辑你的答案并在那里添加你的例子。 – 2016-06-01 03:05:01

0

您可以重命名该文件,使用新名称进行更新,然后重新命名。我已经做到了,但有点沉重。

0

如果你打算使用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(); 
} 
+0

相关[boost interprocess_lock不适用于多个进程](http://stackoverflow.com/questions/6697704/boost-interprocess-file-lock-does-not-work-with-multiple-processes) – 2016-06-01 03:31:56