互斥锁 - 可以通过合并构建集合

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了互斥锁 - 可以通过合并构建集合相关的知识,希望对你有一定的参考价值。

从这里:https://stackoverflow.com/a/5524120/462608

如果要从一组此类对象中锁定多个受互斥锁保护的对象,可以通过合并构建这些对象,则可以

选择使用每个对象恰好一个互斥,允许更多的线程并行工作,

或者为每个对象使用一个对任何可能共享的递归互斥锁的引用,以降低未能将所有互斥锁锁定在一起的概率,

或者为每个对象使用一个与任何可能共享的非递归互斥锁相当的引用,绕过多次锁定的意图。

我只是不明白上面的整个引用。他指的是什么?请用外行的话来解释。

答案

以下是我对引用引用的解释。我希望它既可以理解,也可以与撰写原始答案的人的意图相符。

假设您有一个需要受互斥锁保护的数据结构。您可以选择“粒度”来处理处理这些对象的关键部分。这些选项还可能影响线程可能需要同时获取多个对象的锁定的行为:

  • 每个对象使用一个互斥锁: struct foo { mutex mux; // important data fields... }; 这样做的好处是处理不同对象的线程不会产生争用。如果一个线程需要处理多个对象同时为它们保持锁定(我认为这就是'set merge'的意思),就不需要递归的互斥锁。但是,需要注意避免死锁。
  • 让每个对象引用一个可以与其他对象共享的递归互斥锁: struct foo { recursive_mutex* pmux; // important data fields... }; 由于两个对象实际上可能与单个互斥锁相关联,如果线程1试图锁定对象A并且线程2在对象A和B共享相同的互斥锁时同时尝试锁定对象B,则其中一个线程将阻塞直到另一个线程释放互斥锁。由于互斥锁是递归的,因此单个线程可能会锁定多个对象,即使它们共享相同的互斥锁也是如此。请注意,关于死锁仍然存在相同的警告。 该方案优先于(可能)的优点是,如果线程必须同时锁定多个对象,则该集合中的某些对象将共享一个互斥锁。一旦线程锁定其中一个对象,理论上在尝试锁定下一个对象时阻塞的可能性就会降低。但是,我认为在实践中可能很难证明您将获得此优势,除非您能够真正描述线程的锁定行为以及它们将锁定的对象集(并设置互斥共享以镜像该模型)。
  • 该引用中的最后一项主要是指在上述场景中使用非递归锁。在这种情况下,你需要阻止一个线程试图'重新锁定'一个互斥锁(当然,这不能用非递归互斥锁来完成),所以线程必须以某种方式比较一个它的锁定获取已经获取的锁,以确定它是否应该获取该对象上的锁。如果涉及多个对象,这可能会成为一个复杂的场景,以确保线程已获得完全正确的锁定集。 struct foo { mutex* pmux; // pointer to (possibly shared) non-recursive mutex // important data fields... }; // a set of objects a thread needs to work on in a critical section // the objects possibly share non-recursive mutexes struct foo* pA; struct foo* pB; struct foo* pC; // acquire the necessary locks on all three objects: mutex_lock( pA->pmux); if (pB->pmux != pA->pmux) mutex_lock( pB->pmux); if ((pC->pmux != pA->pmux) && (pC->pmux != pB->p-mux)) mutex_lock( pC->pmux); // releasing the set of mutexes is similar 最好将它们传递给一个能够确保忽略任何重复项的复杂性的函数,而不是手动获取内联互斥体。与之前的方案一样,仍然需要解决避免死锁的问题。

以上是关于互斥锁 - 可以通过合并构建集合的主要内容,如果未能解决你的问题,请参考以下文章

互斥锁 & 共享锁

LockSupport.java 中的 FIFO 互斥代码片段

互斥锁自旋锁读写锁和条件变量

ReentrantReadWriteLock场景应用

java中ReentrantReadWriteLock读写锁的使用

synchronized学习