【问题标题】:Problems with MCS lock implementationMCS 锁实现的问题
【发布时间】:2020-05-21 21:56:26
【问题描述】:

我正在尝试使用原子在 C++ 中实现 MCS 锁。但不幸的是,线程陷入了僵局。一个线程在acquire方法中等待flag变为false,而第二个线程在release方法中卡在do while循环中。所以问题一定是原子地存储/加载下一个节点。任何想法如何调试这个或我做错了什么?

这是我目前所拥有的:

#include <atomic>
#include <iostream>
#include <omp.h>

struct qnode {
  std::atomic<qnode *> next;
  std::atomic<bool> wait;
};

class mcs_lock {
  std::atomic<qnode *> tail;

public:
  void acquire(qnode *p) {
    p->next.store(nullptr);
    p->wait.store(true);

    qnode *prev = tail.exchange(p, std::memory_order_acq_rel);

    if (prev) {
      prev->next.store(p, std::memory_order_release);

      /* spin */
      while (p->wait.load(std::memory_order_acquire))
        ;
    }
  }

  void release(qnode *p) {
    qnode *succ = p->next.load(std::memory_order_acquire);

    if (!succ) {
      if (tail.compare_exchange_strong(p, nullptr, std::memory_order_acq_rel))
        return;

      do {
        succ = p->next.load(std::memory_order_acquire);
      } while (succ == nullptr);
    }

    succ->wait.store(false, std::memory_order_release);
  }
};

int main() {
  mcs_lock lock;
  qnode p;
  int counter = 0;

#pragma omp parallel for default(none) private(p) shared(lock, counter)
  for (int i = 0; i < 100000; i++) {
    lock.acquire(&p);
    ++counter;
    lock.release(&p);
  }

  std::cout << "counter=" << counter << "\n";

  return 0;
}

【问题讨论】:

    标签: c++ multithreading locking openmp


    【解决方案1】:

    问题在于您的发布实现:

        if (!succ) {
          // if this compare-exchange fails, it loads the new value of tail
          // and stores it in p
          if (tail.compare_exchange_strong(p, nullptr, std::memory_order_acq_rel))
            return;
    
          do {
            succ = p->next.load(std::memory_order_acquire);
          } while (succ == nullptr);
        }
    

    如注释所示,失败的比较交换将覆盖p 中的值。这当然是以下循环没有按预期终止的原因。修复很简单:

        if (!succ) {
          auto expected = p;
          if (tail.compare_exchange_strong(expected, nullptr, std::memory_order_acq_rel))
            return;
    
          do {
            succ = p->next.load(std::memory_order_acquire);
          } while (succ == nullptr);
        }
    

    【讨论】:

    • 谢谢!有时你看不到你面前的东西...... :)
    猜你喜欢
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2014-08-19
    • 1970-01-01
    • 2015-08-26
    • 2011-10-23
    • 1970-01-01
    • 2021-06-18
    相关资源
    最近更新 更多