我想从CreatMutex
切换到boost::interprocess::named_mutex
以将我的应用程序限制为单个实例。当应用程序运行并且结束时,两种方法都有效。但是,当应用程序崩溃并使用boost::interprocess::named_mutex
时,锁定不会被释放。我可以使用两个name_mutex来解决这个问题,但我真的不明白这个问题。
为什么在应用程序崩溃但boost::interprocess::named_mutex
发布时,CreatMutex
的锁未释放?有什么区别?
boost::interprocess::named_mutex mutex(boost::interprocess::open_or_create, "my_mutex");
boost::interprocess::scoped_lock<boost::interprocess::named_mutex> lock(mutex, boost::interprocess::try_to_lock);
if(!lock) {
return 1; //exit
}
//application may crash here.
boost::interprocess::named_mutex::remove("my_mutex");
return 1; //exit
答案 0 :(得分:7)
警告:我没有在boost::interprocess
上花费太多时间,所以这些信息只是来自对源的快速检查。也就是说,我已经使用了Windows同步API了,所以这里......
两种进程间同步方法的主要区别在于对象在系统中的存在方式。
使用boost::interprocess::named_mutex
以及系统特定的互斥锁,看起来同步对象在系统上创建为文件。文件的位置基于注册表项(参见注释1)(至少在Boost 1.54.0中)...它的很可能位于Common Application Data文件夹下(参见注释2)。当应用程序崩溃时,在您的情况下,此文件不会被删除。我不确定这是不是设计......但是在应用程序崩溃的情况下,最好不要乱用文件系统,以防万一。
相反,当您使用CreateMutex
时,会在内核模式下创建一个对象,对于命名的互斥锁,可以由多个应用程序访问该对象。通过在创建Mutex时指定名称来获取Mutex的句柄,并且当您在其上调用CloseHandle
时丢失句柄。当没有更多句柄引用它时,会销毁互斥对象。
这一点的重要部分在documentation:
系统会在流程终止时自动关闭句柄。当最后一个句柄关闭时,互斥对象将被销毁。
这基本上意味着Windows将在您申请后进行清理。
请注意,如果您没有执行ReleaseMutex
,并且您的应用程序在它死亡时拥有互斥锁,则等待的线程或进程可能/可能会看到该互斥锁已被放弃({{ 1}}返回WaitForSingleObject
),并获得所有权。
我为没有提供解决方案而道歉,但我希望它能回答你关于两个系统为何采取不同行为的问题。
除此之外,使用注册表项来获取此信息非常糟糕 - 使用WAIT_ABANDONED
会更安全,更具前瞻性。但我离题了。
根据您的操作系统版本,可以是SHGetKnownFolderPath
或%ALLUSERSPROFILE%\Application Data\boost.interprocess
,也可以是其他地方。
答案 1 :(得分:1)
你想要的并不是微不足道的,interprocess_mutex肯定是错误的做法。
你可以做的是通过提供一个卸载析构函数和/或一个catch(...)来删除终止时的互斥锁,但是这不能保证工作,因为如果你终止它就不会这样做该过程直接(来自OS)。也可以在应用程序启动两次时意外删除互斥锁。
一种方法是在程序第一次启动时保护进程标识(例如在共享内存中),并在程序停止时将其删除。每次启动应用程序时都会读取并检查id是否仍在进行中,如果没有,则启动该程序。