为什么这段代码导致死锁?

时间:2012-09-03 04:16:22

标签: c++ pthreads deadlock cilk cilk-plus

我很惊讶地从pstack看到此代码导致死锁!我没有看到相同的原因。

pthread_mutex_t lock;

_Cilk_for (int i = 0; i < N; ++i) {
  int ai = A[i];
  if (ai < pivot) {
    pthread_mutex_lock(&lock);
    A[ia++] = ai;
    pthread_mutex_unlock(&lock);
  }
  else if (ai > pivot) {
    pthread_mutex_lock(&lock);
    A[ib++] = ai;
    pthread_mutex_unlock(&lock);
  }
  else {
    pthread_mutex_lock(&lock);
    A[ic++] = ai;
    pthread_mutex_unlock(&lock);
  }
}

我只是使用互斥锁来确保对A的访问是原子的和序列化的。

  • 此代码导致死锁有什么问题?
  • 有更好的方法来实现这个吗?

3 个答案:

答案 0 :(得分:5)

如果函数中有代码,那么你就不能正确初始化互斥锁。您需要将其设置为PTHREAD_MUTEX_INITIALIZER(对于简单的默认互斥锁)或对其执行pthread_mutex_init()(以满足更复杂的要求)。如果没有正确的初始化,你不知道互斥体的起始状态 - 它可能处于锁定状态只是因为在该位置发生的堆栈看起来像一个锁定的互斥锁。

这就是为什么总是需要以某种方式进行初始化,以便对初始状态毫无疑问。

您可能遇到的另一个潜在问题是:

int ai = A[i];

可能应该使用相同的互斥锁保护该访问权限,否则你可能会以“半状态”读取它(当另一个线程只是更新变量的一部分时)。


而且,我不得不说,我不确定这里是否明智地使用了线程。互斥体的使用很可能会使A[ia++] = ai这样的语句淹没到绝大部分时间用于锁定和解锁互斥锁的程度。它们通常在锁定期间处理的代码更加实用时更有用。

你可能会发现一个非线程的变种会把这个变成一个水(但是,当然,不要相信我的话 - 我的主要优化口号是“测量,不要猜测” )。

答案 1 :(得分:3)

您的pthread_mutex_t lock未正确初始化,因此,由于它是一个局部变量,它可能包含垃圾,并且可能处于奇怪的锁定状态。您应致电pthread_mutex_init或使用lock

初始化PTHREAD_MUTEX_INITIALIZER

正如其他人所抱怨的那样,你并没有明智地使用互斥锁。代码的关键部分太小了。

答案 2 :(得分:1)

在您修复或以其他方式验证您实际上正在初始化lock

之后

pstack可能知道_Cilk_for引入的机制会干扰那些原本合理pthread代码的机制。

快速搜索显示有mutex solutions for use with Cilk - 没有提到混合Cilk和pthreads。它确实看起来像Cilk是pthreads上的一个层 - 所以如果Cilk选择在mutex,周围放置一个包装器,他们很可能这样做是有充分理由的。我建议继续使用Cilk API。

除此之外,你的算法还有一个更基本的问题。 在您的情况下,创建并行线程并同步它们的开销可能使在for循环体中执行代码的成本相形见绌。如果没有并行化,它很可能会运行得更快。