如果您愿意使用 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;
};
现在您可以安全地锁定文件(即您锁定,做一些可能抛出的事情,您总是在退出当前的 {}-block 之前解锁):
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
在公开场合,您创建了锁:
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();
}