3

我很惊讶地看到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 的访问是原子的和序列化的。

  • 这段代码有什么问题导致死锁?
  • 有没有更好的方法来实现这一点?
4

3 回答 3

5

如果那是函数内的代码,那么您没有正确初始化互斥锁。您需要将其设置为PTHREAD_MUTEX_INITIALIZER(对于简单的默认互斥锁)或pthread_mutex_init()对其进行操作(对于更复杂的要求)。如果没有正确的初始化,您将不知道互斥锁从什么状态开始 - 它很可能处于锁定状态,因为该位置的堆栈上发生的任何事情看起来都像是一个锁定的互斥锁。

这就是为什么它总是需要以某种方式初始化,这样就不会怀疑初始状态。

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

int ai = A[i];

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


而且,我不得不说,我不确定这里是否明智地使用了线程。互斥锁的使用很可能会淹没一个语句A[ia++] = ai,以至于绝大多数时间都花在锁定和解锁互斥锁上。它们通常在锁定期间处理的代码更重要的情况下更有用。

您可能会发现一个非线程变体会将这个变体从水中吹走(但是,当然,不要相信我的话——我的主要优化口号是“测量,不要猜测”)。

于 2012-09-03T04:33:31.020 回答
3

pthread_mutex_t lock没有正确初始化,所以,因为它是一个局部变量,它可能包含垃圾,并且可能处于奇怪的锁定状态。您应该调用pthread_mutex_initlock使用PTHREAD_MUTEX_INITIALIZER

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

于 2012-09-03T04:23:34.770 回答
1

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

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

快速搜索显示有与 Cilk 一起使用的互斥解决方案- 没有提到混合 Cilk 和 pthreads。看起来 Cilk 是 pthreads 之上的一层——所以如果 Cilk 选择在周围放置一个包装器,mutex,他们这样做可能是有充分理由的。我建议继续使用 Cilk API。

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

于 2012-09-03T04:46:32.473 回答