【问题标题】:Applying two or more mutexes to a section of code将两个或多个互斥锁应用于一段代码
【发布时间】:2015-05-05 20:31:19
【问题描述】:

我正在研究来自 http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html 的 c++ pthreads 中的互斥锁和死锁

我理解它们,但我只是在一个点上堆叠。我不明白以下代码的问题是什么。你能用简单明了的话解释一下吗?我从这个网站引用:

互斥锁死锁:... 将两个或多个互斥锁应用于一段代码时要小心。如果应用了第一个 pthread_mutex_lock 并且第二个 pthread_mutex_lock 由于另一个线程应用互斥锁而失败,则第一个互斥锁可能最终锁定所有其他线程以防止访问数据,包括持有第二个互斥锁的线程。线程可能会无限期地等待资源空闲,从而导致死锁。最好进行测试,如果发生故障,请释放资源并在重试之前停止。

01  ...
02  pthread_mutex_lock(&mutex_1);
03  while ( pthread_mutex_trylock(&mutex_2) )  /* Test if already locked   */
04  {
05     pthread_mutex_unlock(&mutex_1);  /* Free resource to avoid deadlock */
06         ...
07     /* stall here   */
08     ...
09     pthread_mutex_lock(&mutex_1);
10  }
11  count++;
12  pthread_mutex_unlock(&mutex_1);
13  pthread_mutex_unlock(&mutex_2);
14  ...

提前致谢。

【问题讨论】:

  • 为什么你认为这段代码有问题?它看起来更像是一个如何避免所描述问题的示例。
  • 我认为代码是正确的,但我没看懂它在句子中的意思,他的句子很复杂,因此我认为代码有问题。
  • #Mike Seymour ,我对这句话一无所知:“如果应用了第一个 pthread_mutex_lock 并且第二个 pthread_mutex_lock 由于另一个线程应用互斥锁而失败,则第一个互斥锁最终可能会锁定所有其他线程访问数据,包括持有第二个互斥锁的线程。"

标签: c++ pthreads mutex deadlock


【解决方案1】:

基本上,如果您需要两个互斥锁来执行任务,mutex_1mutex_2,如果 thread_A 抓取 mutex_1thread_B 抓取 mutex_2,它们就会陷入僵局,因为它们都在等待另一个互斥体可用,但它们永远不会,因为另一个互斥体也在等待。

这就是为什么您通常会强制执行可以获取互斥锁的命令。例如,您必须先获取mutex_1,然后再尝试获取mutex_2。这样你就不能在没有mutex_1的情况下拥有mutex_2,所以没有机会造成死锁。

     Thread_A                Thread_B
        |                       |
        |                       |
   lock(mutex_1)                |            // Thread_A got mutex_1
        |                       |
        |                  lock(mutex_2)     // Thread_B got mutex_2
        |                       |
        |                       |
  trylock(mutex_2)              |            // Thread_A wants mutex_2
        |                 trylock(mutex_1)   // Thread_B wants mutex_1
        |                       |

由于时间原因,这些线程现在处于死锁状态。两者都在等待一个他们永远不会得到的互斥锁,因为另一个线程在完成工作之前不会解锁它持有的互斥锁。

在您的代码示例中,请注意他们所做的第一件事是锁定 mutex_1。然后他们在mutex_2 上旋转直到可用。这是执行命令mutex_1 然后mutex_2

【讨论】:

  • 假设所有线程总是尝试按照您的代码显示的顺序以1 然后2 获取互斥锁,是的,它应该可以避免死锁。
  • 在这个例子中,不止一个互斥锁被应用到一段代码。作者的意思是说“......并且第二个 pthread_mutex_lock 由于另一个线程应用互斥锁而失败......”你能用简单的话解释一下这句话的意思吗?
  • 我想我明白了,你解释了一种可能的死锁情况,在你给出的图中,多个线程可能会导致死锁。为了避免这种糟糕的情况,我们应该强制使用带有顺序的线程。我的例子就是这样做的,对吗?该任务分别强制锁定 mutex1,然后是 mutex2。类似地,我可以编写一个任务,分别强制锁定 mutex2,然后是 mutex1。然后线程1执行task1,thread2执行task2,没有死锁的可能。
  • 对不起,我的例子“这个任务分别强制锁定 mutex1,然后是 mutex2。同样,我可以编写一个任务,分别强制锁定 mutex2,然后是 mutex1。”导致死锁。但是,如果有多个线程执行其中一项任务,则不会出现死锁
【解决方案2】:

如果你锁定了一个互斥体,然后等待第二个,第一个仍然被锁定,所以在你等待的时候没有其他人可以得到它。这很糟糕,所以也许在你等待的时候解锁第一个互斥锁。代码显示了如何做到这一点。

如果另一个线程有您正在等待的互斥锁,并且需要您的互斥锁(它不应该这样做,除非设计搞砸了),那么这非常糟糕 - 两个线程将永远等待,从而导致“死锁” " - 你肯定需要在等待的时候解锁第一个。

但在这种情况下,您应该正确修复它(如下一节所述) - 始终以明确定义的顺序锁定两个互斥锁。

【讨论】:

  • 想想类似的情况,一个线程锁了mutex1,然后又锁了mutex2。那么这两个都安全吗:“首先解锁mutex1然后解锁mutex2”和“首先解锁mutex2然后解锁mutex1”?
  • @metis 如果互斥锁获取的初始顺序正确,则解锁互斥锁的顺序无关紧要。
猜你喜欢
  • 2013-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-09
  • 2017-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多