我正在开发一个适用于Windows的C ++项目,需要一个很好的互斥实现来同步黑白进程(即winapi的包装)。我目前正在使用boost :: interprocess :: named_mutex,但是我注意到如果其中一个进程崩溃 - 互斥锁永远保持锁定状态(即使重启后!)。谷歌搜索这件事证实这实际上是行为。
坦率地说,我不知道在任何项目下这种行为是如何被接受的。存在错误,进程崩溃 - 这只是意味着一个微小的错误可能导致系统再也无法工作......不可接受!
所以我的问题是:
任何人都可以推荐具有“正常”行为的不同实现(即 - 在崩溃时互斥会被废弃,系统重启后“重置”正常工作)?跨平台显然更好,但绝对不是必须的。
出于好奇 - 升级怎么可能让这种行为成为现实?
谢谢!
答案 0 :(得分:4)
documentation for boost::interprocess解释了不同类的持久性。在named_mutex的情况下,它被列为内核或文件系统。从这里我们可以假设Windows实现使用Filesystem,这就是重启系统后它仍然存在的原因。
根据您的情况,您可以为每个进程将自己的文件写入磁盘,然后在进程安全关闭时将其删除。如果fie存在,则重新启动进程时必须进行不正常的关闭,并且可以使用boost::interprocess::named_mutex::remove静态函数来删除互斥锁。
答案 1 :(得分:0)
看看StlSoft的process_mutex。 Crossplatform(使用platformstl组件而不是OS特定的winstl或unixstl版本)和标题。
答案 2 :(得分:0)
为此,我使用了自己的互斥锁,因为我不想仅为此功能添加某些重量级库的依赖项。它用于生产代码中,并在我们的单元测试中涵盖-如果发现任何问题,请告诉我。
但这只是Windows解决方案。
用法示例:
NamedSystemMutex m{ L"MyMutex" };
std::lock_guard<NamedSystemMutex> lock{ m };
标题为SystemMutex.h的标题:
#pragma once
#include <string>
#include <windows.h> // Just needed for HANDLE
// Provides a system-wide, recursive, named lock.
// This class satisfies requirements of C++11 concept "Lockable", i.e. can be (and should be) used with unique_lock etc.
class NamedSystemMutex
{
public:
explicit NamedSystemMutex(const std::wstring& name);
~NamedSystemMutex();
// Moveable, not copyable
NamedSystemMutex(const NamedSystemMutex& other) = delete;
NamedSystemMutex(NamedSystemMutex&& other) = default;
NamedSystemMutex& operator=(const NamedSystemMutex& other) = delete;
NamedSystemMutex& operator=(NamedSystemMutex&& other) = default;
void lock();
void unlock();
bool try_lock();
private:
HANDLE handle_{};
};
实施:
#include "NamedSystemMutex.h"
#include <stdexcept>
NamedSystemMutex::NamedSystemMutex(const std::wstring& name) {
handle_ = CreateMutexW(nullptr, FALSE, name.c_str());
if (handle_ == NULL) {
throw std::runtime_error("Creation of mutex failed");
}
}
NamedSystemMutex::~NamedSystemMutex() {
const BOOL result = CloseHandle(handle_);
if (result == FALSE) {
// Error: Failed to close mutex handle (Error ignored since we are in destructor)
}
}
void NamedSystemMutex::lock() {
const auto result = WaitForSingleObject(handle_, INFINITE);
if (result == WAIT_ABANDONED) {
// Warning: Lock obtained, but on an abandoned mutex (was not correctly released before, e.g. due to a crash)
}
else if (result != WAIT_OBJECT_0) {
throw std::runtime_error("Failed to acquire lock");
}
}
void NamedSystemMutex::unlock() {
const BOOL result = ReleaseMutex(handle_);
if (result == FALSE) {
throw std::runtime_error("Failed to release lock: calling thread does not own the mutex");
}
}
bool NamedSystemMutex::try_lock() {
const auto result = WaitForSingleObject(handle_, 0);
if (result == WAIT_TIMEOUT) {
return false;
}
if (result == WAIT_OBJECT_0) {
return true;
}
throw std::runtime_error("Failed to acquire lock");
}