源码:
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(); }
引申过来的