folly库高性能PackedSyncPtr探究

源码:

template <class T>
class PackedSyncPtr {
  // This just allows using this class even with T=void.  Attempting
  // to use the operator* or operator[] on a PackedSyncPtr<void> will
  // still properly result in a compile error.
  typedef typename std::add_lvalue_reference<T>::type reference;

 public:
  /*
   * If you default construct one of these, you must call this init()
   * function before using it.
   *
   * (We are avoiding a constructor to ensure gcc allows us to put
   * this class in packed structures.)
   */
  void init(T* initialPtr = nullptr, uint16_t initialExtra = 0) {
    auto intPtr = reinterpret_cast<uintptr_t>(initialPtr);
    CHECK(!(intPtr >> 48));
    data_.init(intPtr);
    setExtra(initialExtra);
  }

  /*
   * Sets a new pointer.  You must hold the lock when calling this
   * function, or else be able to guarantee no other threads could be
   * using this PackedSyncPtr<>.
   */
  void set(T* t) {
    auto intPtr = reinterpret_cast<uintptr_t>(t);
    auto shiftedExtra = uintptr_t(extra()) << 48;
    CHECK(!(intPtr >> 48));
    data_.setData(intPtr | shiftedExtra);
  }

  /*
   * Get the pointer.
   *
   * You can call any of these without holding the lock, with the
   * normal types of behavior you'll get on x64 from reading a pointer
   * without locking.
   */
  T* get() const {
    return reinterpret_cast<T*>(data_.getData() & (-1ull >> 16));
  }
  T* operator->() const { return get(); }
  reference operator*() const { return *get(); }
  reference operator[](std::ptrdiff_t i) const { return get()[i]; }

  // Synchronization (logically const, even though this mutates our
  // locked state: you can lock a const PackedSyncPtr<T> to read it).
  void lock() const { data_.lock(); }
  void unlock() const { data_.unlock(); }
  bool try_lock() const { return data_.try_lock(); }

  /*
   * Access extra data stored in unused bytes of the pointer.
   *
   * It is ok to call this without holding the lock.
   */
  uint16_t extra() const {
    return data_.getData() >> 48;
  }

  /*
   * Don't try to put anything into this that has the high bit set:
   * that's what we're using for the mutex.
   *
   * Don't call this without holding the lock.
   */
  void setExtra(uint16_t extra) {
    CHECK(!(extra & 0x8000));
    auto ptr = data_.getData() & (-1ull >> 16);
    data_.setData((uintptr_t(extra) << 48) | ptr);
  }

 private:
  PicoSpinLock<uintptr_t> data_;
} FOLLY_PACK_ATTR;

其实这个库主要使用了PicoSpinLock原子自旋锁来保存数据,前16位保存引用技术,后48位保存指针地址,其实这个只能在64位系统运行,可以从这个函数可以看出来

  void setExtra(uint16_t extra) {
    CHECK(!(extra & 0x8000));
    auto ptr = data_.getData() & (-1ull >> 16);
    data_.setData((uintptr_t(extra) << 48) | ptr);
  }

基本上锁操作都是从PicoSpinLock

  void lock() const { data_.lock(); }
  void unlock() const { data_.unlock(); }
  bool try_lock() const { return data_.try_lock(); }

引申过来的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值