返回

极少共享访问下 Windows 系统资源锁定最佳实践

windows

高效锁定 Windows 系统资源:应对极少共享访问情况

问题概况

在 C++11 中,我们面临着一个棘手的锁定时机选择问题。我们的 C++ 类管理着一系列规则,需要确保在添加或删除规则时不会进行任何检查,但由于添加和删除规则的情况极其罕见,因此在 99.9% 的检查情况下,不需要进行锁定。

潜在解决方案

有多种潜在解决方案,包括:

  • std::mutex: 最简单的方法,但即使在 99.9% 不需要锁定时也必须保持锁定,会造成不必要的开销。
  • 临界区 (Critical Section): 比 std::mutex 慢,尤其是在 Windows 8.1+ 中。
  • WinAPI 互斥体: Windows 系统中的原语,非常高效,适合写入操作罕见的情况。
  • 读写锁: 允许多个线程同时读取资源,但只能允许一个线程写入资源。

推荐解决方案:WinAPI 互斥体

考虑到极少需要共享访问的情况,WinAPI 互斥体 是我们的最佳选择。互斥体在 Windows 系统中非常高效,非常适合这种场景,其中写入操作很少见。

示例实现

以下示例代码展示了如何使用 WinAPI 互斥体:

#include <Windows.h>

class RuleList {
private:
    HANDLE mutex;
    std::list<Rule> rules;

public:
    RuleList() {
        // 创建互斥体
        mutex = CreateMutex(NULL, FALSE, NULL);
    }

    ~RuleList() {
        // 释放互斥体
        CloseHandle(mutex);
    }

    void addRule(const Rule& rule) {
        // 获取互斥体锁
        WaitForSingleObject(mutex, INFINITE);

        // 添加规则
        rules.push_back(rule);

        // 释放互斥体锁
        ReleaseMutex(mutex);
    }

    void removeRule(const Rule& rule) {
        // 获取互斥体锁
        WaitForSingleObject(mutex, INFINITE);

        // 删除规则
        rules.remove(rule);

        // 释放互斥体锁
        ReleaseMutex(mutex);
    }

    bool check(const PID& pid) {
        // 无需锁定,因为规则不会在检查期间发生改变
        for (const Rule& rule : rules) {
            if (rule.appliesTo(pid)) {
                return true;
            }
        }
        return false;
    }
};

优点

  • 高效,特别是对于共享访问极少的情况
  • 易于实现
  • 与 Windows 系统高度集成

缺点

  • 需要使用 Windows 专用 API
  • 可能比其他方法更难以移植到其他平台

常见问题解答

1. 为什么在没有竞争的情况下使用互斥体?

为了确保在添加或删除规则时不会进行任何检查,无论并发情况如何。

2. 是否可以同时拥有多个互斥体?

是的,一个类可以拥有多个互斥体,每个互斥体用于保护不同的资源或操作。

3. 互斥体如何防止死锁?

WinAPI 互斥体实现了死锁检测和预防机制。

4. 如何正确处理互斥体的错误?

在创建、获取或释放互斥体时,应检查错误代码并采取适当措施。

5. 是否有其他非锁定的机制可以解决此问题?

可以考虑使用原子操作或基于版本号的并发控制。然而,这些方法可能并不总是可行,具体取决于具体场景。

总结

通过使用 WinAPI 互斥体,我们可以在极少需要共享访问的情况下高效地锁定 Windows 系统资源。这种方法易于实现,与 Windows 系统高度集成,并且提供所需的效率。