我需要打開一個文件,對其進行讀取鎖定,然後嘗試獲取寫入鎖定,但在讀取鎖定失敗時保持讀取鎖定。LockFileEx讀取/寫入升級/降級
這對POSIX使用fcntl鎖定效果很好。
在Windows中,我可以使用LockFileEx來獲取文件鎖定。我可以讀取和寫入鎖(共享和排他)。
但是,似乎在Windows中,我必須採取獨佔寫鎖第一個,然後添加讀鎖定。這與我在POSIX上做的相反,它會導致我的抽象層出現問題。當我在POSIX中按照該順序執行操作時,我通過讀取鎖定來丟失寫入鎖定,因爲fcntl取代了現有鎖定,而不像Windows那樣添加鎖定。
我可以用#ifdefs改變鎖定順序在呼叫站點,但我正在尋找好的想法來修復我的抽象代碼。
// This is the header file
struct LockFileImpl;
class LockFile {
protected:
boost::scoped_ptr<LockFileImpl> p;
public:
LockFile(const File &);
virtual ~LockFile();
void unlock() const;
void rd_lock() const;
void wr_lock() const;
bool rd_try() const;
bool wr_try() const;
};
class LockFileRead : public LockFile{
public:
LockFileRead(const File &f) : LockFile(f)
{ rd_lock(); }
};
class LockFileWrite : public LockFile{
public:
LockFileWrite(const File &f) : LockFile(f)
{ wr_lock(); }
};
// This is the Win32 implementation file. There's a different one for POSIX.
struct LockFileImpl
{
handle_t hFile;
bool rd_locked;
bool wr_locked;
LockFileImpl(handle_t x) : hFile(x), rd_locked(false), wr_locked(false)
{}
};
LockFile::LockFile(const File &f)
: p(new LockFileImpl(f.handle()))
{
}
LockFile::~LockFile()
{
unlock();
}
void LockFile::unlock() const
{
if(p->wr_locked) {
throw_win32_err_if(UnlockFile(p->hFile, 0, 0, 1, 0) == 0);
p->wr_locked = false;
}
if(p->rd_locked) {
throw_win32_err_if(UnlockFile(p->hFile, 0, 0, 1, 0) == 0);
p->rd_locked = false;
}
}
void LockFile::rd_lock() const
{
OVERLAPPED over = {0};
over.Offset = 0;
throw_win32_err_if(!LockFileEx(p->hFile, 0, 0, 1, 0, &over));
p->rd_locked = true;
if(p->wr_locked) {
throw_win32_err_if(UnlockFile(p->hFile, 0, 0, 1, 0) == 0);
p->wr_locked = false;
}
}
void LockFile::wr_lock() const
{
OVERLAPPED over = {0};
over.Offset = 0;
throw_win32_err_if(!LockFileEx(p->hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &over));
p->wr_locked = true;
}
bool LockFile::rd_try() const
{
OVERLAPPED over = {0};
over.Offset = 0;
bool r = !!LockFileEx(p->hFile, LOCKFILE_FAIL_IMMEDIATELY, 0, 1, 0, &over);
if(r) {
p->rd_locked = true;
if(p->wr_locked) {
throw_win32_err_if(UnlockFile(p->hFile, 0, 0, 1, 0) == 0);
p->wr_locked = false;
}
}
return r;
}
bool LockFile::wr_try() const
{
OVERLAPPED over = {0};
over.Offset = 0;
bool r = !!LockFileEx(p->hFile, LOCKFILE_FAIL_IMMEDIATELY|LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &over);
if(r) {
p->wr_locked = true;
}
return r;
}
您是否需要在如此低的水平上操作?我的意思是,底層的狀態機顯然是不同的,如果你以這種方式直接暴露它們,你的班級在每個平臺上的表現都會有所不同。但是,如果您決定希望自己的類能夠抽象出正確的狀態模型,那麼您需要對底層平臺調用進行不同的命令,以便在暴露的抽象方面獲得一致的結果。 – 2010-07-06 13:32:06
@克里斯:不,我不需要低水平運作。我需要能夠進行文件鎖定並升級並將其降級爲寫入/排除,而不會丟失讀取/共享鎖定。我也可以使用命名的Mutex或類似的東西在Windows上完全替代它。 – 2010-07-06 16:10:20