首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++11递归自旋锁实现

C++11递归自旋锁实现
EN

Stack Overflow用户
提问于 2016-06-26 02:12:27
回答 1查看 1.9K关注 0票数 0

接下来,我尝试实现一个递归的自旋锁,如下所示。

代码语言:javascript
运行
复制
class SpinLock {
public:
  SpinLock() : lock_owner(lock_is_free), lock_count(0) {
  }

  inline bool tryLock() {
    if (lock_owner != std::this_thread::get_id()) {
      bool locked = lock_owner.compare_exchange_strong(lock_is_free,
          std::this_thread::get_id(), std::memory_order_acquire,
          std::memory_order_relaxed);
      if (locked) {
        lock_count++;
      }
      return locked;
    }

    lock_count++;
    return true;
  }

  inline void lock() {
    if (lock_owner != std::this_thread::get_id()) {
      while(!lock_owner.compare_exchange_weak(lock_is_free,
            std::this_thread::get_id(), std::memory_order_acquire,
            std::memory_order_relaxed));
      assert(lock_owner == std::this_thread::get_id());
    } else {
      printf("Recursive locking\n");
    }

    lock_count++;
  }

  inline void unlock() {
    assert(lock_owner == std::this_thread::get_id());
    assert(lock_count != 0);

    --lock_count;
    if (lock_count == 0) {
      lock_owner.store(lock_is_free, std::memory_order_release);
    }
  }

  inline bool isOwner() {
    return lock_owner == std::this_thread::get_id();
  }

  inline bool isSet() {
    return lock_owner != lock_is_free;
  }

private:
  std::thread::id lock_is_free;
  std::atomic<std::thread::id> lock_owner;
  int lock_count;
};

但是,当我尝试使用多个线程进行锁定时,方法似乎并不能确保互斥。我在这里做错什么了?

1

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-06-26 04:53:39

正如注释中所指出的,如果条件为false,compare_exchange_weak将替换第一个参数的内容,因此lock_is_free已损坏。

此外,这是无效的代码,因为compare_exchange_weak按位顺序比较存储在atomic变量中的对象的值,就像使用std::memcmp进行比较一样。并且std::thread::id类型的对象不是一个整体类型,并且具有特殊的过载来进行比较。pthread_t (pthread_equal)也是如此,所以本质上您依赖于实现定义的行为。

您可以通过运行以下代码来确认这一点

代码语言:javascript
运行
复制
#include <type_traits>
#include <iostream>
#include <thread>
#include <pthread.h>
using std::cout;
using std::endl;

int main() {
    cout << std::boolalpha << std::is_integral<std::thread::id>::value << endl;
    cout << std::boolalpha << std::is_integral<decltype(pthread_self())>::value
        << endl;

    return 0;
}

在这种情况下,为什么不仅仅重载memcpymemcmp来使用std::thread::id呢?优先选择cplusplus.com都确认没有任何保证。即使重载memcpy (无论是全局的还是在std命名空间中)都不能在我的系统上使用我的标准库。我怀疑在大多数其他系统(标准库和编译器组合)上也不会这样做,原因有二:

  1. compare_exchange_weak可能不会在引擎盖下使用memcpymemcmp,并且可能会提交自己的实现。
  2. 尽管不需要在将指针传递给void*之前先转换一个指向memcpy的指针,但是无论如何,memcmp可能会选择默认的实现,这是不正确的。

请参阅下面的代码,以了解我在第二点中的意思。

代码语言:javascript
运行
复制
void func(void*) {
    cout << "void*" << endl;
}
void func(int*) {
    cout << "int*" << endl;
}

int main() {
    int a = 1;
    func(&a);
    func(reinterpret_cast<void*>(a));

    return 0;
}

要回答您的问题,使用compare_exchange_weakstd::thread::id是不正确的(“不是可移植的”可能更好)代码。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38034648

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档