)
引言因为c提供了很多的锁信号量还有辅助创建锁的工具但是没有提供跨平台性很好的自旋锁所以我们利用辅助创建锁的工具只需要提供lock(),try_lock(),unlock()三个API这样子就可以创建出我们的自旋锁。自旋锁自旋锁SpinLock就是线程抢不到锁时不进入休眠而是在 CPU 上不停地循环检查直到锁被释放自旋锁一般要配合CPU的优化因为不停的忙等会导致CPU的性能下降所以我们需要告诉CPU这个地方不需要一直忙等而是时不时来看一眼。inline void cpu_relax() noexcept { #if defined (__x86_64__) || defined (__i386__) _mm_pause(); #endif }这个是我们自己写的自旋锁我们的锁是std::atomic_flag一般实现自旋锁就是这个因为这个只可以设置false / true解释一下lock函数外层循环里面查看锁是否可以拥有如果是false那么就设置为true并且返回原来的状态false这个样子不仅仅表示拥有了锁而且跳出了循环。当第二个线程来的时候因为被设置为了true所以返回true并且不会改变锁的状态。进入内部的循环并且因为如果外部没有释放锁那么一直是true所以内部一直循环里面也做了CPU的优化。当外部锁被释放跳出内部循环重新进入外部循环然后跳出外部循环。class SpinLock { public: using Lock std::lock_guardSpinLock; SpinLock() noexcept default; ~SpinLock() noexcept default; SpinLock(const SpinLock) delete; SpinLock operator(const SpinLock) delete; void lock() noexcept { while(mutex_.test_and_set(std::memory_order_acquire)) { while(mutex_.test(std::memory_order_relaxed)) { cpu_relax(); } } } // 不可以忽略掉返回值也就是要bool a try_lock(); [[nodiscard]] bool try_lock() noexcept { return !mutex_.test_and_set(std::memory_order_acquire); } void unlock() noexcept { mutex_.clear(std::memory_order_release); } private: std::atomic_flag mutex_ ATOMIC_FLAG_INIT; // 0 };最后我们使用的时候只需要传入我们的SpinLock即可因为辅助的创建锁工具是一个模板类这个类里面只要实现了特定的接口那么就可以使用这个锁。template typename Mutex std::chrono::nanoseconds BenchmarkMutex(std::size_t thread_count) { Mutex mutex; Counter_ 0; const auto elapsed BenchmarkThreads(thread_count, [](std::size_t, u64 operations) { for(u64 index 0; index operations; index) { std::lock_guardMutex lock(mutex); Counter_; } }); if (Counter_ ! target_) { throw std::runtime_error(mutex correctness check failed); } return elapsed; }总结本篇文章到这里就结束了希望可以帮助大家理解~~~