无法获取文件锁定

Posted

技术标签:

【中文标题】无法获取文件锁定【英文标题】:can't acquire a lock on a file 【发布时间】:2017-03-02 16:35:13 【问题描述】:

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 个小时里都被这个卡住了。

谁能告诉我这有什么问题?

【问题讨论】:

将您的程序更改为在lockf 刚刚返回非零值的每个地方 打印strerror(errno)。再次运行它们。告诉我们他们打印的内容。 它没有返回非零值。我有日志,但它们没有被打印,因为它总是返回 0。现在将这些日志更改编辑到代码中。 您不应该创建某种对象,这样您就不必一直打开文件吗?在is_file_locked() 中,您打开但不关闭文件描述符;您将用完文件描述符。您不会关闭lock_file()unlock_file() 中的文件描述符,但这会让储物柜有责任关闭文件(从而解锁文件)。我相信,析构函数和 RAII 会让生活变得更简单。 添加了关闭更改但仍然无法正常工作...我们是否应该关闭 lock_file 中的文件而不解锁?我只关闭了 unlock_file 和 is_file_locked。更新了代码。 作为信息,我也有一个类版本的文件柜,但它也不起作用。 【参考方案1】:

您在 POSIX 文件锁中遇到了一个更严重的设计错误。您可能不知道这一点,因为您只阅读了lockf manpage,而不是fcntl manpage,所以这是fcntl 手册页的重要部分:

如果进程关闭任何引用文件的文件描述符,则 所有进程对该文件的锁定都被释放,无论 获得锁的文件描述符。

这意味着,在你的这段代码中

    if (Utils::FileLocker::lock_file("hello.txt", fd))
    
            std::ofstream out("hello.txt");
            out << "hello ding dong" << std::endl;
            out.close();

当您调用 out.close() 时,您会失去对文件的锁定,即使 out 是不同于您在 lock_file 中使用的操作系统级别的“打开文件描述”! p>

为了安全地使用 POSIX 锁,您必须确保在要锁定的文件上调用 open() 每个进程一次且仅一次,您绝不能复制文件描述符,并且您必须仅当您准备好放下锁时再将其关闭。因为可能没有任何方法(甚至使用不可移植的扩展)来从文件描述符构造 iostreams 对象,或者从 iostreams 对象中提取文件描述符,所以阻力最小的路径是只使用操作系统级 I/O 原语(openclosereadwritefcntllseeklseekftruncate)以及需要对其应用 POSIX 锁的文件。

【讨论】:

在这种情况下我还有一个问题,将 close(fd) 将关闭 ofstream 使用的所有描述符(如果它用于打开同一个文件并且我没有调用 ofstream.close( ))? 不,ofstream 有自己的“打开文件描述”,close(fd) 不会影响它。但是,锁将在ofstream.close()close(fd)第一个 处被释放,因为锁与进程 相关联,而不是与打开的文件相关联。 好的,我想问的是,如果我调用close(fd),还需要调用ofstream.close()吗? 是的,我就是这么说的。请注意,我还说过您可能需要完全停止使用 iostream。

以上是关于无法获取文件锁定的主要内容,如果未能解决你的问题,请参考以下文章

Vmware无法获取快照信息 锁定文件失败

无法获取快照信息:锁定文件失败

使用windows c++ LockFIle() 锁定文件然后从中获取流?

如果文件存在,如何锁定文件,不要创建它?

如何获取锁定文件的大小?

I/O:FileLock