boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为

Posted

技术标签:

【中文标题】boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为【英文标题】:boost::interprocess::file_lock erroneous behavior when used with std::ostream 【发布时间】:2020-09-09 01:12:06 【问题描述】:

我正在尝试使用file_lock 来限制同一程序的多个实例同时运行(实现this answer 中提到的内容)。我在Linux 上使用1.66 版本的boost。

在锁定文件之前,我确保该文件存在(通过使用std::ofstreamstd::ios::app 打开它)。我注意到一件事,如果我们关闭流,file_lock 会自动解锁,因此允许同一程序的多个实例同时运行。

file_lock 被自动释放,下面的程序无法运行。

int main(int argc, char *argv[])

    namespace bipc = boost::interprocess;
    if (argc < 2)
        return 0;

    std::string path = argv[1];
    std::string lock_path = "/var/lock/" + path + ".lock";

    std::ofstream stream(lock_path, std::ios::app);

    bipc::file_lock lock(lock_path.c_str());

    if (!lock.try_lock())
        throw std::runtime_error("Multiple instance");

    std::cout << "Running" << std::endl;
    stream.close();
    while (true)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    return 0;

但是,下面的两个程序可以工作。

看起来如果我们在尝试获取 file_lock 时打开了一个文件,那么我们需要保持该文件处于打开状态,直到我们想要持有锁为止。如果我们关闭文件,那么锁就会自动释放。我不确定这是否是一个错误。有人可以帮我解释这种行为的原因吗?

int main(int argc, char *argv[])

    namespace bipc = boost::interprocess;
    if (argc < 2)
        return 0;

    std::string path = argv[1];
    std::string lock_path = "/var/lock/" + path + ".lock";

    std::ofstream stream(lock_path, std::ios::app);
    bipc::file_lock lock(lock_path.c_str());

    if (!lock.try_lock())
        throw std::runtime_error("Multiple instance");

    std::cout << "Running" << std::endl;
    while (true)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    return 0;

int main(int argc, char *argv[])

    namespace bipc = boost::interprocess;
    if (argc < 2)
        return 0;

    std::string path = argv[1];
    std::string lock_path = "/var/lock/" + path + ".lock";

    
        std::ofstream stream(lock_path, std::ios::app);
    
    bipc::file_lock lock(lock_path.c_str());

    if (!lock.try_lock())
        throw std::runtime_error("Multiple instance");

    std::cout << "Running" << std::endl;
    while (true)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    return 0;

【问题讨论】:

【参考方案1】:

我找到了原因。这是由于boost::interprocess::file_lock 是使用Classic POSIX File-locks 实现的。

link 解释了 POSIX 锁的问题,因此也解释了 boost file_locks。

更令人不安的是,该标准规定,只要进程关闭与锁定文件对应的任何文件描述符,就会删除进程持有的所有锁,即使这些锁是使用仍然打开的文件描述符创建的。正是这个细节让大多数程序员大吃一惊,因为它要求程序在确定可以删除该文件上的锁之前不要关闭文件描述符。

看起来我应该使用 flock 或其他使用 flock 的平台库。

【讨论】:

以上是关于boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为的主要内容,如果未能解决你的问题,请参考以下文章

boost::interprocess::file_lock 与 std::ostream 一起使用时的错误行为

Linux下 boost::interprocess::create_or_open_file 改变文件类型

boost interprocess file_lock 实际上对目标文件做了啥?

boost interprocess file_lock 无法锁定它不拥有的文件

boost::memory-mapping 的问题 ~500MB,外部 USB 文件

managed_mapped_file 是不是能够因分配而增加文件大小?