【问题标题】:Threading causes unexpected crash线程导致意外崩溃
【发布时间】:2015-11-10 14:18:44
【问题描述】:

我不知道问题出在哪里,但是当我在 OS X 上运行我的代码时,它运行良好,但在 Linux 上我的程序无法运行。

这是我的代码:

Thread() {
                       - some other code - 
           randLane1 = rand() % 16; 
           randLane2 = rand() % 16; 

           while(randLane1 == randLane2) {
               randLane2 = rand() % 16; 
           }
           pthread_mutex_lock(&mutexFineLock[randLane1]);
           pthread_mutex_lock(&mutexFineLock[randLane2]);
           // if Rouge picked a lane that has already been fired at, look for a free lane
           while(Gallery->Get(randLane1) != white) {
              pthread_mutex_unlock(&mutexFineLock[randLane1]);
              randLane1 = rand() % 16; 
              pthread_mutex_lock(&mutexFineLock[randLane1]);
           }   
           pthread_mutex_unlock(&mutexFineLock[randLane2]);

}

现在这是踢球者,如果我删除 pthread_mutex_lock(&mutexFineLock[randLane2]);pthread_mutex_unlock(&mutexFineLock[randLane2]);,它将毫无问题地运行。但是导致错误的原因是什么?如果我只是简单地打开和关闭一个锁而没有死锁的可能性,有什么问题?

如果我将pthread_mutex_unlock(&mutexFineLock[randLane2]); 放在我的pthread_mutex_lock(&mutexFineLock[randLane2]); 之后,这会进一步增加我的困惑。

注意:在我的代码中pthread_mutex_unlock(&mutexFineLock[randLane2]); 有一个目的,它被放置在更下方以执行上面代码中未显示的操作。我正在调试我的错误,并意识到它甚至无法通过 for 循环。

如果有人知道我的问题出在哪里,那就太好了。

【问题讨论】:

  • 它是如何崩溃的?您是否尝试过在调试器中运行它,例如gdb?
  • 始终以与锁定相反的顺序解锁您的锁,否则您确实有可能出现死锁。或者尝试重构代码,使您一次只需要一把锁。
  • 假设我们有两个线程,A 和 B。线程 A 锁定两个锁,而线程 B 被阻塞等待第一个锁。然后线程 A 进入循环并解锁第一个锁,并被线程 B 抢占,线程 B 获得第一个锁,然后被阻塞等待第二个锁。线程 A 再次开始运行,但由于线程 B 现在持有它,因此无法取回第一个锁。死锁。
  • @QQCompi 如果您的数组有十二个元素,rand() % 16 不是生成有效索引的好方法。
  • 我希望 pthread_mutex_t mutexFineLock[12] 真的是 [16] 或者你有另一个错误。

标签: c++ multithreading locks


【解决方案1】:

例子:

第一个线程已锁定 mutexFineLock[randLane1=13],然后 mutexFineLock[randLane2=12] 并开始工作。

第二个线程已锁定 mutexFineLock[randLane1=3],然后尝试锁定已锁定的 mutexFineLock[randLane2=12],等待。

在处理第一个线程时,已释放 mutexFineLock[randLane1=13],然后尝试锁定被第二个线程锁定的 mutexFineLock[randLane1=13%16=3]。等待。

由于死锁,终于大家都在等待了。

当您立即解锁 randLane2 时,第二个线程不必等待,因此可以正常工作。

这是个问题。

【讨论】:

    【解决方案2】:

    你自己制造了一个死锁。 (至少只要您不向我们展示您的互斥锁定义)。

        while(Gallery->Get(randLane1) != white) {
            pthread_mutex_unlock(&mutexFineLock[randLane1]);
            randLane1 = rand() % 16; <---------------- PHAIL
            pthread_mutex_lock(&mutexFineLock[randLane1]);
        }   
    

    如果randLane1 等于randLane2,您尝试再次重新锁定同一个互斥锁。

    避免由于锁顺序错误而导致的死锁

        pthread_mutex_lock(&mutexFineLock[randLane2]);
        pthread_mutex_lock(&mutexFineLock[randLane1]);
    

    重试获取不同的通道 1 和 2。 编辑:将 randLane2 更改为 1。

        while(Gallery->Get(randLane1) != white) {
            pthread_mutex_unlock(&mutexFineLock[randLane1]);
            randLane1 = rand() % 16;
            while(randLane1 == randLane2) { // retry
               randLane1 = rand() % 16; 
            }
            pthread_mutex_lock(&mutexFineLock[randLane1]);
        }   
    

    【讨论】:

    • 我明白你在说什么,你知道有什么办法可以克服这个僵局吗?
    • 是的,您可以重试,还可以修复锁定/解锁顺序。
    • @QQCompi,小bug,把retry改成randLane1。
    【解决方案3】:

    死锁的经典例证。解锁的顺序不是锁定的相反顺序。 lock(m1); lock(m2); unlock(m1) 是一本直接的灾难秘诀。您应该始终以与锁定相反的顺序解锁互斥锁(或其他锁)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-28
      • 2018-08-12
      • 1970-01-01
      • 2011-10-17
      相关资源
      最近更新 更多