繁体   English   中英

C ++ 11递归自旋锁实现

[英]C++11 Recursive Spinlock Implementation

在[1]之后,我尝试如下实现递归自旋锁。

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] https://codereview.stackexchange.com/questions/95590/c11-recursive-atomic-spinlock

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

此外,这不是有效的代码,因为compare_exchange_weak按位顺序比较存储在atomic变量中的对象的值,就好像使用std::memcmp进行了比较。 而且类型为std::thread::id的对象不是整数类型,并且具有特殊的重载用于比较。 pthread_tpthread_equal )也是如此,因此从本质pthread_equal ,您依赖于实现定义的行为。

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

#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;
}

在这种情况下,为什么不重载memcpymemcmpstd::thread::id一起使用呢? cppreferencecplusplus.com都确认没有保证。即使使用标准库在我的系统上,即使重载memcpy (在全局和std名称空间中)也无法正常工作。 我怀疑它也不能在大多数其他系统(标准库和编译器组合)上使用,原因有两个:

  1. compare_exchange_weak可能在compare_exchange_weak不使用memcpymemcmp ,并且可能会滚动其自己的实现
  2. 尽管不需要将指针强制转换为void*然后再将其传递给memcpymemcmp可能会选择默认的实现方式,但这并不正确

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

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;
}

要回答您的问题,请对带有std::thread::id compare_exchange_weak使用不正确的代码(“不便携”可能更好)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM