互斥锁(Mutex)和自旋锁(Spinlock)是在并发编程中常用的同步机制,用于保护共享资源的访问。
互斥锁是一种阻塞锁,当一个线程持有了互斥锁后,其他想要获取该锁的线程将被阻塞挂起,直到持有锁的线程释放它。互斥锁适用于较长时间的临界区域或者资源竞争激烈的情况。它使用操作系统提供的原语实现,因此会引入上下文切换和内核开销。
自旋锁是一种忙等待锁,在尝试获取锁时不断地循环检查是否可以获得。如果不能获取到,则继续循环等待,直到获取到为止。自旋锁适用于临界区域很短且竞争不激烈的情况,避免了上下文切换带来的开销。但是,在多核处理器上使用自旋锁可能会导致空转浪费CPU资源。
举个例子来说明:
假设有一个共享变量 count 需要保护,并行的增加其值。在使用互斥锁和自旋锁两种方式实现保护时:
- 互斥锁示例:
#include <mutex>
std::mutex mtx;
int count = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx);
count++;
}
在这个例子中,使用了 <mutex>
头文件提供的互斥锁 std::mutex
和 RAII(Resource Acquisition Is Initialization)技术,确保只有一个线程能够同时访问临界区域。
- 自旋锁示例:
#include <atomic>
std::atomic_flag flag = ATOMIC_FLAG_INIT;
int count = 0;
void increment() {
while (flag.test_and_set(std::memory_order_acquire)) {}
count++;
flag.clear(std::memory_order_release);
}
在这个例子中,使用了 <atomic>
头文件提供的原子操作和自旋锁 std::atomic_flag
。通过不断尝试获取锁,直到成功为止,并保证对共享资源的访问是原子性的。
需要根据具体情况选择适合的同步机制,互斥锁适用于长时间占用临界区域或者竞争激烈的情况,而自旋锁适用于临界区域很短且竞争不激烈的情况。
内容由零声教学AI助手提供,问题来源于学员提问