-
Notifications
You must be signed in to change notification settings - Fork 385
ipc::spin_lock
mutouyun edited this page Dec 9, 2025
·
3 revisions
轻量级自旋锁,用于短时间的临界区保护。适用于竞争不激烈、持锁时间极短的场景。
namespace ipc {
class spin_lock {
public:
void lock() noexcept;
void unlock() noexcept;
};
} // namespace ipcipc::spin_lock是一个基于原子操作的自旋锁实现,不使用系统调用。当锁被占用时,线程会在循环中不断尝试获取锁("自旋"),而不是进入睡眠状态。
特点:
- ✅ 无系统调用开销,极快的lock/unlock
- ✅ 适合持锁时间极短(微秒级)的场景
⚠️ CPU消耗高,不适合长时间持锁⚠️ 仅适用于进程内同步,不支持进程间同步
| 成员函数 | 说明 |
|---|---|
lock |
获取自旋锁 |
unlock |
释放自旋锁 |
void lock() noexcept;获取自旋锁。如果锁已被占用,当前线程会自旋等待(busy-waiting)直到获得锁。
自旋策略:
- 前4次尝试:不做任何操作,直接重试
- 4-16次:使用CPU pause指令,降低功耗
- 16-32次:调用
std::this_thread::yield()让出CPU - 32次以上:睡眠1毫秒
返回值:无
异常:不抛出异常(noexcept)
void unlock() noexcept;释放自旋锁。
返回值:无
异常:不抛出异常(noexcept)
注意:只有持有锁的线程才能解锁。
#include "libipc/rw_lock.h" // spin_lock定义在此文件中
#include <thread>
#include <vector>
ipc::spin_lock g_lock;
int g_counter = 0;
void increment() {
for (int i = 0; i < 10000; ++i) {
g_lock.lock();
++g_counter;
g_lock.unlock();
}
}
int main() {
std::vector<std::thread> threads;
for (int i = 0; i < 4; ++i) {
threads.emplace_back(increment);
}
for (auto& t : threads) {
t.join();
}
std::cout << "Counter: " << g_counter << std::endl; // 应该是40000
return 0;
}// 创建一个RAII风格的锁守卫
class spin_lock_guard {
ipc::spin_lock& lock_;
public:
explicit spin_lock_guard(ipc::spin_lock& lock) : lock_(lock) {
lock_.lock();
}
~spin_lock_guard() {
lock_.unlock();
}
// 禁止拷贝
spin_lock_guard(const spin_lock_guard&) = delete;
spin_lock_guard& operator=(const spin_lock_guard&) = delete;
};
// 使用RAII守卫
void safe_increment() {
spin_lock_guard guard(g_lock);
++g_counter; // 自动加锁和解锁
}// 使用spin_lock保护
ipc::spin_lock lock;
int value = 0;
void update_with_lock() {
lock.lock();
value = value + 1; // 可以执行复杂操作
lock.unlock();
}
// 使用atomic(仅适合简单操作)
std::atomic<int> atomic_value{0};
void update_atomic() {
atomic_value.fetch_add(1, std::memory_order_relaxed);
}✅ 适合使用spin_lock的场景:
- 临界区非常小(几条指令)
- 持锁时间极短(微秒级)
- 竞争不激烈
- 高性能要求,不能容忍系统调用开销
❌ 不适合使用spin_lock的场景:
- 临界区较大或持锁时间长
- 竞争激烈(多个线程频繁等待)
- 需要进程间同步(应使用
ipc::sync::mutex) - 临界区内有IO操作或系统调用
在无竞争情况下的性能(Intel i5-4300U):
| 锁类型 | Lock/Unlock时间 |
|---|---|
| spin_lock | ~20ns |
| std::mutex | ~100ns |
| ipc::sync::mutex | ~100ns |
注意:在高竞争情况下,spin_lock可能比mutex更慢,因为它会浪费CPU循环。
class spin_lock {
std::atomic<std::uint32_t> lc_ { 0 };
public:
void lock() noexcept {
for (unsigned k = 0;
lc_.exchange(1, std::memory_order_acquire);
yield(k)) ;
}
void unlock() noexcept {
lc_.store(0, std::memory_order_release);
}
};关键点:
- 使用
std::atomic<uint32_t>作为锁标志 -
lock()使用exchange原子操作尝试将0设置为1 -
unlock()将标志设回0 - 使用
memory_order_acquire和memory_order_release保证内存可见性 - 自适应的yield策略减少CPU浪费
- 不可递归:同一线程不能对已持有的spin_lock再次加锁(会死锁)
- 不可拷贝:spin_lock对象不能拷贝或移动
- 进程内使用:仅用于同一进程内的线程同步
- 公平性:不保证公平性,可能出现饥饿
- 异常安全:建议使用RAII包装类
- 持锁时间:保持持锁时间尽可能短
- 避免嵌套:不要在持有spin_lock时获取其他锁
-
ipc::rw_lock- 读写锁(也是自旋锁实现) -
ipc::sync::mutex- 进程间互斥锁 - rw_lock.h - 头文件文档