用于 Windows 的 C++ 互斥锁
Posted
技术标签:
【中文标题】用于 Windows 的 C++ 互斥锁【英文标题】:C++ Mutex for Windows 【发布时间】:2012-10-16 07:53:51 【问题描述】:我正在开发一个适用于 Windows 的 C++ 项目,并且需要一个良好的互斥锁实现来同步黑白进程(即 winapi 的包装)。我目前正在使用 boost::interprocess::named_mutex,但是我注意到如果其中一个进程崩溃 - 互斥锁将永远保持锁定状态(即使在重新启动后!)。谷歌搜索这件事证实了这实际上是行为。
坦率地说,我看不出这种行为在任何项目中都是可以接受的。错误存在,进程崩溃 - 这只是意味着一个小错误可能导致系统永远无法再次工作......不可接受!
所以我的问题是:
谁能推荐一个具有“正常”行为的不同实现(即互斥锁在崩溃时被放弃,并且在系统重新启动后将“重置”以正常工作)?跨平台显然更好,但绝对不是必须的。
出于好奇 - boost 怎么可能导致这种行为?
谢谢!
【问题讨论】:
【参考方案1】:documentation for boost::interprocess 解释了不同类的持久性。在 named_mutex 的情况下,它被列为内核或文件系统。由此我们可以假设 Windows 实现是使用文件系统,这就是它在您重新启动系统后仍然存在的原因。
根据您的情况,您可以为每个进程将自己的文件写入磁盘,然后在进程安全关闭时将其删除。如果 fie 存在,则重新启动进程时,一定是不干净的关闭,您可以使用 boost::interprocess::named_mutex::remove 静态函数来删除互斥锁。
【讨论】:
“为每个进程将你自己的文件写入磁盘,然后在进程安全关闭时将其删除”:更好的是,你可以CREATE_NEW
FILE_ATTRIBUTE_TEMPORARY
文件,即使进程崩溃,Windows 也会自动删除。如果您收到 ERROR_FILE_EXISTS,则表示已使用互斥锁。虽然当然只使用 CreateMutex
和 WaitForSingleObject
(总共大约 10 行 C++ 包装器)就可以了,并且没有 OP 的问题。【参考方案2】:
看看 StlSoft 的process_mutex。跨平台(使用platformstl 组件,而不是操作系统特定的winstl 或unixstl 版本)和仅标头。
【讨论】:
【参考方案3】:我为此推出了自己的互斥锁,因为我不想仅仅为了这个功能而向某些重量级库添加依赖项。它用于生产代码并包含在我们的单元测试中 - 如果您发现任何问题,请告诉我。
这是一个仅限 Windows 的解决方案。
使用示例:
NamedSystemMutex m L"MyMutex" ;
std::lock_guard<NamedSystemMutex> lock m ;
Header NamedSystemMutex.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");
【讨论】:
以上是关于用于 Windows 的 C++ 互斥锁的主要内容,如果未能解决你的问题,请参考以下文章