[英]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
帮助器更容易除非未处理,否则显示的异常应该不是问题。 如果您使用的是 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.