繁体   English   中英

正确使用 boost::interprocess::named_mutex

[英]Using boost::interprocess::named_mutex correctly

我在使用 named_mutex 时遇到问题,我试图用它来确定我的应用程序的另一个实例是否正在运行。

我定义了一个全局变量:

named_mutex dssMutex{ open_or_create, "DeepSkyStacker.Mutex.UniqueID.12354687" };

然后在 main() 中我写道:

    if (!dssMutex.try_lock()) firstInstance = false;

在 main() 的末尾,在我完成了所有捕获的事情之后:

dssMutex.unlock();

我遇到的问题是,当这是我的程序在系统中的唯一实例时(刚重启后),try_lock() 返回 false。 我还在调试日志中看到了这一点(这可能只是 try_lock() 的产物):

Exception thrown at 0x00007FFB838C4FD9 in DeepSkyStacker.exe: Microsoft C++ exception: boost::interprocess::interprocess_exception at memory location 0x00007FF5FFF7EF00.

那我做错了什么?

谢谢大卫

三件事:

  • 如果try_lock返回 false,你不应该unlock
  • 你应该是异常安全的,使用scoped_lock帮助器更容易
  • Boost 的进程间锁定原语不是健壮的互斥体。 这意味着如果您的进程在没有解锁的情况下被硬终止,锁将被卡住。 据我所知,Windows 上的实现包含一个“启动时间”字段,用于在重新启动后恢复锁定,因此您描述的场景应该不是问题。

例外

除非未处理,否则显示的异常应该不是问题。 如果您使用的是 Visual Studio,则可以将调试器配置为在抛出或未处理的异常时中断。 对该消息最好的解释是它是在内部处理的。 最糟糕的解释是你没有处理它。 在那种情况下,它会解释锁没有被释放。

请注意,异常可能是由于try_lock失败后尝试unlock引起的?

代码示例

以下是我将如何使用延迟作用域锁来实现异常安全:

#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;

int main(int, char** argv) {
    bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};

    bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
    bool const firstInstance = lk.try_lock();

    std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
    std::this_thread::sleep_for(1s);
    std::cout << " Bye\n" << std::flush;
}

Coliru无法处理它,但这是在本地执行的操作:

在此处输入图像描述

信号处理

现在,如前所述,这仍然不够健壮,但是您可以通过至少处理例如 SIGINT 来使其不那么糟糕(当您在终端中按 Ctrl-C 时,POSIX 会发生什么):

#include <boost/asio.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <iostream>
#include <thread>
namespace bip = boost::interprocess;
using namespace std::chrono_literals;

int main(int, char** argv) {
    boost::asio::thread_pool ioc(1);
    boost::asio::signal_set ss(ioc, SIGINT, SIGTERM);
    ss.async_wait([](auto ec, int s) {
        if (ec == boost::asio::error::operation_aborted)
            return;
        std::cerr << "signal " << s << " (" << ec.message() << ")" << std::endl;
    });

    bip::named_mutex dssMutex{bip::open_or_create, "UniqueID.12354687"};

    bip::scoped_lock<bip::named_mutex> lk(dssMutex, bip::defer_lock);
    bool const firstInstance = lk.try_lock();

    std::cout << argv[0] << (firstInstance?" FRIST!":" SECOND") << std::flush;
    std::this_thread::sleep_for(1s);

    std::cout << " Bye\n" << std::flush;

    ss.cancel();
    ioc.join();
}

现在可以中断进程了:

for a in {1..10}; do sleep "0.$RANDOM"; ./one; done& 
for a in {1..10}; do sleep "0.$RANDOM"; ./two; done&
sleep 3; pkill -INT -f ./one;
sleep 5; pkill -INT -f ./two

在此处输入图像描述

如果仔细观察,处理程序现在实际上没有执行任何操作。 很可能你想确保它干净地关闭main

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM