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,然后锁定找到的互斥锁。即使另一个线程介入并解锁互斥体,引用计数也不会降为零,互斥体也不会被移除。