【问题标题】:Fine grained locking细粒度锁定
【发布时间】:2012-02-20 01:17:50
【问题描述】:

假设我们有一个大数组和许多线程在该数组中的具体索引上运行。两个线程不能同时对一个索引进行操作,一个应该等到另一个完成。还有一个蹩脚的问题:如何在 Linux/C/C++ 中对数组的每个索引实现test-and-set 锁定?

【问题讨论】:

标签: c++ c linux multithreading mutex


【解决方案1】:

对于细粒度锁定,请使用读/写锁数组(正如 Carey Hickling 建议的那样)。哈希索引值并通过位掩码(或使用模数)对其进行过滤以选择要使用的锁。

这有效地将索引拆分为 N 个存储桶,其中 N 是您创建的锁的数量。选择 2 的幂作为易于位掩码的锁数(掩码 = N - 1)。在这种情况下,唯一的缺点是您不仅锁定了一个特定的索引,而且锁定了每个索引,这些索引在散列时与同一个锁定指针对齐。

话虽如此,您创建的锁越多,锁的粒度就越细(16 可能是一个很好的起点)。读锁也与 rw_locks 共享,因此您只需要担心在写期间等待锁。

【讨论】:

  • 绝对出色的解决方案,我来到这里的想法是,我必须对数组使用一个锁,这会限制并行性,或者每个元素一个互斥锁,这可能是大量的锁。谢谢!
  • 有没有简单的方法可以映射到几个桶中?例如,您会使用std::hash%16 吗?
【解决方案2】:

您要么需要一个简单的互斥锁,然后执行:

    mutex.lock();
    //access array using index
    mutex.unlock();

或者 POSIX 提供了读写锁。因此,您可以这样做:

    pthread_rwlock_rdlock(rw_lock_ptr);
    // read the array
    pthread_rwlock_unlock(rw_lock_ptr);

还有:

    pthread_rwlock_wrlock(rw_lock_ptr);
    // update the array
    pthread_rwlock_unlock(rw_lock_ptr);

这允许用于读取操作的共享锁和用于写入操作的排它锁。

我建议您为数组的每个元素设置一个类或一对,并实现上述其中一个。如果您在类的读取/更新函数中隐藏互斥锁,那么您可以更轻松地限制互斥锁的范围并轻松避免死锁。

【讨论】:

    【解决方案3】:

    使数组元素类型成为同步的东西。如果你想互斥你的数据,你可以有一个std::pair<T, std::mutex>;如果您可以在每次访问时使用自旋锁,您可以拥有std::pair<T, std::atomic<bool>>。然后就让每个数组访问通过同步数据获取对元素的独占访问。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      相关资源
      最近更新 更多