【C++并发编程】(十二)自旋锁

(十二)自旋锁

与传统的互斥锁相同,自旋锁也是一种用于保护共享资源的同步机制,不同都是,自旋锁在尝试获取锁时不会立即进入阻塞状态,而是循环检查锁的状态(自旋),“忙等”直到获取到锁为止。

在多线程并发的环境中,线程的阻塞和唤醒通常需要涉及操作系统的调度器,进行线程上下文的切换。这些操作会消耗大量的CPU时间和系统资源。自旋锁通过忙等待的方式,避免了线程阻塞和系统调度器介入,从而减少了这部分开销。但也需要注意,自旋锁适用于临界区较小且短时间内能够获取锁的情况。如果临界区较大,自旋锁会导致线程长时间占用CPU资源,反而降低系统的整体性能。

C++中可以通过原子类型 std::atomic_flag来实现自旋锁。std::atomic_flag 只有两种状态:被设置(set)和未被设置(clear),其主要成员函数包括:

  • clear(): 将 atomic_flag 设为 false
  • test_and_set(): 如果 atomic_flag 已经被设置,返回 true,否则返回 false 并设置atomic_flagtrue

cleartest_and_set 的内存顺序默认都是 memory_order_seq_cst

自旋锁示例代码:

#include <iostream>
#include <thread>
#include <atomic>
#include <vector>

// 使用std::atomic_flag实现自旋锁。
class SpinLock {
private:
    std::atomic_flag flag = ATOMIC_FLAG_INIT; // 初始化为未设置状态

public:

    void lock() {
        while (flag.test_and_set()) { 	// 使用test_and_set原子操作不断尝试获取锁
            // 自旋等待锁被释放
        }
    }


    void unlock() {
        flag.clear(); 	// 使用clear原子操作释放锁
    }
};

class SpinLockExample {
private:
    SpinLock spinlock; // 自旋锁
    int counter;       // 计数器

public:
    SpinLockExample() : counter(0) {}
	

    void increment() {
        for (int i = 0; i < 1000; ++i) {
            spinlock.lock();
            ++counter; //  临界区操作:锁定期间递增计数器
            spinlock.unlock();
        }
    }

    int getCounter() const {
        return counter;
    }
};

void threadFunction(SpinLockExample& example) {
    example.increment();
}

int main() {
    SpinLockExample example;

    std::vector<std::thread> threads;
	// 启动多个线程调用increment方法。
    for (int i = 0; i < 10; ++i) {
        threads.push_back(std::thread(threadFunction, std::ref(example)));
    }

    for (auto& t : threads) {
        t.join();
    }

    std::cout << "Final counter value: " << example.getCounter() << std::endl;

    return 0;
}

结果:

Final counter value: 10000
上一篇:可视化工具选择指南:助力企业数字化转型和新质生产力发展


下一篇:内网安全:权限维持的各种姿势