无法获取文件的锁
can't acquire a lock on a file
FileLocker_wo.h
#include <string>
namespace Utils
{
namespace FileLocker
{
bool lock_file(std::string aFileName, int& aFileDescriptor);
bool unlock_file(int& aFileDescriptor);
bool is_file_locked(std::string aFileName);
};
}
FileLocker_wo.cpp
namespace Utils
{
namespace FileLocker
{
bool lock_file(std::string aFileName, int& aFileDescriptor)
{
aFileDescriptor = open(aFileName.c_str(), O_RDWR);
if (aFileDescriptor != -1)
{
if (lockf(aFileDescriptor, F_TLOCK, 0) == 0)
{
return true;
}
std::cout << strerror(errno) << std::endl;
}
return false;
}
bool unlock_file(int& aFileDescriptor)
{
if (lockf(aFileDescriptor, F_ULOCK, 0) == 0)
{
std::cout << "unloced file" << std::endl;
close(aFileDescriptor);
return true;
}
close(aFileDescriptor);
return false;
}
bool is_file_locked(std::string aFileName)
{
int file_descriptor = open(aFileName.c_str(), O_RDWR);
if (file_descriptor != -1)
{
int ret = lockf(file_descriptor, F_TEST, 0);
if (ret == -1 && (errno == EACCES || errno == EAGAIN))
{
std::cout << "locked by another process" << std::endl;
close(file_descriptor);
return true;
}
if (ret != 0)
{
std::cout << "return value is " << ret << " " << strerror(errno) << std::endl;
}
}
close(file_descriptor);
return false;
}
}
}
p1.cpp
#include <iostream>
#include <fstream>
#include "FileLocker_wo.h"
int main()
{
int fd = -1;
if (Utils::FileLocker::lock_file("hello.txt", fd))
{
std::ofstream out("hello.txt");
out << "hello ding dong" << std::endl;
out.close();
std::cout << "locked" << std::endl;
sleep(5);
if (Utils::FileLocker::unlock_file(fd))
{
std::cout << "unlocked" << std::endl;
}
}
return 0;
}
p2.cpp
#include "FileLocker_wo.h"
#include <iostream>
#include <fstream>
int main()
{
int max_trys = 2;
int trys = 0;
bool is_locked = false;
do
{
is_locked = Utils::FileLocker::is_file_locked("hello.txt");
if (!is_locked)
{
std::cout << "not locked" << std::endl;
break;
}
std::cout << "locked" << std::endl;
sleep(1);
++trys;
}
while(trys < max_trys);
if (!is_locked)
{
std::string s;
std::ifstream in("hello.txt");
while(getline(in,s))
{
std::cout << "s is " << s << std::endl;
}
}
return 0;
}
我正在尝试在一个进程中获取文件锁,并使用 lockf (p1.cpp, p2.cpp).
检查其他进程中该文件是否有任何锁
在 p1.cpp 中,我正在锁定文件 hello.txt 并等待 5 秒。与此同时,我开始 p2.cpp 并检查其他进程是否有任何锁,但总是没有锁>我在过去的 2 小时里一直坚持这个。
谁能告诉我这是哪里出了问题?
您遇到了 POSIX 文件锁中最严重的设计错误之一。您可能不知道这一点,因为您只阅读了 lockf
manpage, not the fcntl
manpage,所以这里是 fcntl
联机帮助页的重要部分:
- If a process closes any file descriptor referring to a file, then
all of the process's locks on that file are released, regardless of
the file descriptor(s) on which the locks were obtained.
这意味着,在您的这段代码中
if (Utils::FileLocker::lock_file("hello.txt", fd))
{
std::ofstream out("hello.txt");
out << "hello ding dong" << std::endl;
out.close();
当您调用 out.close()
时,您失去了对文件的锁定, 即使 out
是不同的 OS 级别 "open file description" 比你在 lock_file
!
中使用的要多
为了安全地使用 POSIX 锁,您必须确保对要锁定的文件调用 open()
一次并且每次仅调用一次 process,你绝不能复制文件描述符,并且只有在准备好释放锁时才能再次关闭它。因为可能没有任何方法(甚至使用不可移植的扩展)从文件描述符构造 iostreams 对象,或从 iostreams 对象中提取文件描述符,阻力最小的路径是使用 only OS 级 I/O 原语 (open
, close
, read
, write
, fcntl
, lseek
, ftruncate
) 以及需要应用 POSIX 锁的文件。
FileLocker_wo.h
#include <string>
namespace Utils
{
namespace FileLocker
{
bool lock_file(std::string aFileName, int& aFileDescriptor);
bool unlock_file(int& aFileDescriptor);
bool is_file_locked(std::string aFileName);
};
}
FileLocker_wo.cpp
namespace Utils
{
namespace FileLocker
{
bool lock_file(std::string aFileName, int& aFileDescriptor)
{
aFileDescriptor = open(aFileName.c_str(), O_RDWR);
if (aFileDescriptor != -1)
{
if (lockf(aFileDescriptor, F_TLOCK, 0) == 0)
{
return true;
}
std::cout << strerror(errno) << std::endl;
}
return false;
}
bool unlock_file(int& aFileDescriptor)
{
if (lockf(aFileDescriptor, F_ULOCK, 0) == 0)
{
std::cout << "unloced file" << std::endl;
close(aFileDescriptor);
return true;
}
close(aFileDescriptor);
return false;
}
bool is_file_locked(std::string aFileName)
{
int file_descriptor = open(aFileName.c_str(), O_RDWR);
if (file_descriptor != -1)
{
int ret = lockf(file_descriptor, F_TEST, 0);
if (ret == -1 && (errno == EACCES || errno == EAGAIN))
{
std::cout << "locked by another process" << std::endl;
close(file_descriptor);
return true;
}
if (ret != 0)
{
std::cout << "return value is " << ret << " " << strerror(errno) << std::endl;
}
}
close(file_descriptor);
return false;
}
}
}
p1.cpp
#include <iostream>
#include <fstream>
#include "FileLocker_wo.h"
int main()
{
int fd = -1;
if (Utils::FileLocker::lock_file("hello.txt", fd))
{
std::ofstream out("hello.txt");
out << "hello ding dong" << std::endl;
out.close();
std::cout << "locked" << std::endl;
sleep(5);
if (Utils::FileLocker::unlock_file(fd))
{
std::cout << "unlocked" << std::endl;
}
}
return 0;
}
p2.cpp
#include "FileLocker_wo.h"
#include <iostream>
#include <fstream>
int main()
{
int max_trys = 2;
int trys = 0;
bool is_locked = false;
do
{
is_locked = Utils::FileLocker::is_file_locked("hello.txt");
if (!is_locked)
{
std::cout << "not locked" << std::endl;
break;
}
std::cout << "locked" << std::endl;
sleep(1);
++trys;
}
while(trys < max_trys);
if (!is_locked)
{
std::string s;
std::ifstream in("hello.txt");
while(getline(in,s))
{
std::cout << "s is " << s << std::endl;
}
}
return 0;
}
我正在尝试在一个进程中获取文件锁,并使用 lockf (p1.cpp, p2.cpp).
检查其他进程中该文件是否有任何锁在 p1.cpp 中,我正在锁定文件 hello.txt 并等待 5 秒。与此同时,我开始 p2.cpp 并检查其他进程是否有任何锁,但总是没有锁>我在过去的 2 小时里一直坚持这个。
谁能告诉我这是哪里出了问题?
您遇到了 POSIX 文件锁中最严重的设计错误之一。您可能不知道这一点,因为您只阅读了 lockf
manpage, not the fcntl
manpage,所以这里是 fcntl
联机帮助页的重要部分:
- If a process closes any file descriptor referring to a file, then all of the process's locks on that file are released, regardless of the file descriptor(s) on which the locks were obtained.
这意味着,在您的这段代码中
if (Utils::FileLocker::lock_file("hello.txt", fd))
{
std::ofstream out("hello.txt");
out << "hello ding dong" << std::endl;
out.close();
当您调用 out.close()
时,您失去了对文件的锁定, 即使 out
是不同的 OS 级别 "open file description" 比你在 lock_file
!
为了安全地使用 POSIX 锁,您必须确保对要锁定的文件调用 open()
一次并且每次仅调用一次 process,你绝不能复制文件描述符,并且只有在准备好释放锁时才能再次关闭它。因为可能没有任何方法(甚至使用不可移植的扩展)从文件描述符构造 iostreams 对象,或从 iostreams 对象中提取文件描述符,阻力最小的路径是使用 only OS 级 I/O 原语 (open
, close
, read
, write
, fcntl
, lseek
, ftruncate
) 以及需要应用 POSIX 锁的文件。