c++ 我怎么写单进程named_mutex?
c++ how can I write single-process named_mutex?
我需要一个 class 允许我 lock/unlock 特定名称(或简单的索引),我不希望它是多处理的,所以我可以 运行 我的应用程序的多个实例。另外我想避免使用特定于系统的 API,只是 std 或 boost。 (为了简单起见,我们可以说:同时使用的names/indexes的最大数量是100)
很遗憾,我没有适合您的用法示例,我只是感兴趣是否可以制作。
我试图找到类似的东西,但我只找到了 boost::interprocess::named_mutex
和一些 WinApi 方法,例如 CreateMutexW
.
我也尝试编写自己的代码(如下),但它绝对不完美并且至少有一个潜在的错误。
那么,有没有人有任何建议、代码想法或已经存在的 classes?
提前致谢
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::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();
没有死锁!可以先解锁 master,然后锁定找到的互斥锁。即使另一个线程介入并解锁互斥体,引用计数也不会降为零,互斥体也不会被移除。
我需要一个 class 允许我 lock/unlock 特定名称(或简单的索引),我不希望它是多处理的,所以我可以 运行 我的应用程序的多个实例。另外我想避免使用特定于系统的 API,只是 std 或 boost。 (为了简单起见,我们可以说:同时使用的names/indexes的最大数量是100)
很遗憾,我没有适合您的用法示例,我只是感兴趣是否可以制作。
我试图找到类似的东西,但我只找到了 boost::interprocess::named_mutex
和一些 WinApi 方法,例如 CreateMutexW
.
我也尝试编写自己的代码(如下),但它绝对不完美并且至少有一个潜在的错误。
那么,有没有人有任何建议、代码想法或已经存在的 classes?
提前致谢
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::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();
没有死锁!可以先解锁 master,然后锁定找到的互斥锁。即使另一个线程介入并解锁互斥体,引用计数也不会降为零,互斥体也不会被移除。