c++ 如何编写单进程named_mutex?
Posted
技术标签:
【中文标题】c++ 如何编写单进程named_mutex?【英文标题】:c++ how can I write single-process named_mutex? 【发布时间】:2019-12-17 12:28:50 【问题描述】:我需要一个允许我锁定/解锁特定名称(或只是索引)的类,并且我不希望它是多处理的,因此我可以运行我的应用程序的多个实例。此外,我想避免使用特定于系统的 API,只是 std 或 boost。 (为简单起见,我们可以说:同时使用的名称/索引的最大数量为 100)
不幸的是,我没有给你使用示例,我只是感兴趣是否可以制作。
我试图找到类似的东西,但我找到的只是boost::interprocess::named_mutex
和一些WinApi 方法,比如CreateMutexW
。
我也尝试编写自己的代码(如下),但它绝对不完美,并且至少有一个潜在的错误。
那么,有没有人有任何建议、代码想法或已经存在的类?
提前致谢
class IndexMutex
public:
void Lock(uint32_t id);
void Unlock(uint32_t id);
private:
struct IndexLock
static constexpr uint32_t unlocked = ~0u;
void Lock(uint32_t id)
index_ = id;
mutex_.lock();
void Unlock()
mutex_.unlock();
index_ = unlocked;
bool IsLocked() const
return index_ != unlocked;
std::atomic<uint32_t> index_ = unlocked;
std::mutex mutex_;
;
std::array<IndexLock, 100> mutexes_;
std::mutex masterMutex_;
;
void IndexMutex::Lock(uint32_t id)
if (id == IndexLock::unlocked)
return;
const std::lock_guard<std::mutex> __guard masterMutex_ ;
uint32_t possibleId = IndexLock::unlocked;
for (uint32_t i = 0; i < mutexes_.size(); ++i)
if (mutexes_[i].index_ == id)
masterMutex_.unlock();
// POTENTIAL BUG: TIME GAP
mutexes_[i].Lock(id);
return;
// Searching for unlocked mutex in the same time.
if (possibleId == IndexLock::unlocked && !mutexes_[i].IsLocked())
possibleId = i;
if (possibleId == IndexLock::unlocked)
throw std::runtime_error "No locks were found." ;
// We are sure here, that mutex can't be locked
// because we were protected by the muster mutex all that time.
mutexes_[possibleId].Lock(id);
void IndexMutex::Unlock(uint32_t id)
if (id == IndexLock::unlocked)
return;
const std::lock_guard<std::mutex> __guard masterMutex_ ;
for (auto& lock : mutexes_)
if (lock.index_ == id)
lock.Unlock();
return;
throw std::runtime_error "No mutexes there found by specified index." ;
【问题讨论】:
目前还不太清楚为什么需要所有这些机器。为什么一个普通的 std::array 不适合你? 你这是什么意思?如果您建议为每个可能的索引使用单独的互斥锁,这将是很大的内存开销(我们最多可以有 4294967294 个不同的索引,以及更多的名称)。如果你的意思是为了简单起见从我的代码中删除musterMutex_
(只具有可以接受索引的互斥体的数组),那么当两个线程可以锁定相同的索引时我们会遇到问题..
好吧,看起来你想要一个(线程安全的)map<int, mutex>
之类的东西。
在某种程度上是的,但是如何使 map您想要一个引用计数互斥映射,受主互斥锁保护。
方面的实现std::map<int, std::pair<int, std::mutex>>
会做这项工作。
锁操作是这样工作的(未经测试的伪代码):
master.lock()
std::pair<int, std::mutex>& m = mymap[index]; //inserts a new one if needed
m.first++;
master.unlock();
m.second.lock();
解锁操作:
master.lock();
std::pair<int, std::mutex>& m = mymap[index];
m.second.unlock();
m.first--;
if (m.first==0) mymap.remove(index);
master.unlock();
没有死锁!可以先解锁主控,然后锁定找到的互斥锁。即使另一个线程干预并解锁互斥体,引用计数也不会降至零,并且互斥体也不会被删除。
【讨论】:
非常感谢)我想这是我寻找的解决方案) 我唯一建议的是在解锁操作中使用map::find
而不是operator[]
,所以我们确定索引实际上在地图中。如果万一我们得到不正确的索引,则解锁后该互斥锁的计数将变为-1。
这只是一个粗略的轮廓,根据需要调整。以上是关于c++ 如何编写单进程named_mutex?的主要内容,如果未能解决你的问题,请参考以下文章
boost::named_mutex: 最后一个进程关闭时安全清理