浅谈C++ 多线程锁处理

一、基本介绍

        在C++中,多线程编程同样需要处理线程安全问题,C++11及更高版本提供了一套标准库来支持多线程编程,包括锁的处理。

二、常见锁处理方式

互斥锁(std::mutex)

  • std::mutex是最基本的锁类型,提供了互斥访问共享资源的能力。
  • 它不允许一个线程多次获得锁(即不可重入)。

#include <mutex>
#include <thread>

std::mutex mtx;
int shared_data = 0;

void increment() {
    mtx.lock();
    shared_data++;
    mtx.unlock();
}

递归互斥锁(std::recursive_mutex)

  • std::recursive_mutex允许同一个线程多次获得锁,这在递归函数调用中非常有用。
#include <mutex>
#include <thread>

std::recursive_mutex mtx;
int shared_data = 0;

void increment() {
    mtx.lock();
    shared_data++;
    // 可以再次调用 increment() 而不会死锁
    increment();
    mtx.unlock();
}

读写锁(std::shared_mutex)

  • C++17引入了std::shared_mutex,它允许多个线程同时读取共享资源,但写入时需要独占访问。
#include <shared_mutex>
#include <thread>

std::shared_mutex rw_mutex;
int shared_data = 0;

void read() {
    std::shared_lock<std::shared_mutex> lock(rw_mutex);
    // 读取 shared_data
}

void write(int value) {
    std::unique_lock<std::shared_mutex> lock(rw_mutex);
    shared_data = value;
}

条件变量(std::condition_variable)

  • std::condition_variable用于线程间的同步,允许一个线程等待某个条件成立。
#include <mutex>
#include <condition_variable>
#include <thread>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker_thread() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });
    // 执行工作
}

void main_thread() {
    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();
}

原子操作(std::atomic)

  • 对于简单的数据类型,可以使用原子类型std::atomic来保证操作的原子性,而不需要使用锁。
#include <atomic>
#include <thread>

std::atomic<int> shared_data(0);

void increment() {
    shared_data++;
}

锁的封装(std::lock_guard 和 std::unique_lock)

  • std::lock_guardstd::unique_lock是RAII(资源获取即初始化)风格的锁封装,它们在构造时自动获取锁,在析构时自动释放锁。
#include <mutex>
#include <thread>

std::mutex mtx;

void increment() {
    std::lock_guard<std::mutex> lock(mtx);
    shared_data++;
}

void long_task() {
    std::unique_lock<std::mutex> lock(mtx);
    // 执行一些任务
    lock.unlock();
    // 执行不需要锁的任务
}

一次性初始化(std::once_flag 和 std::call_once)

  • std::once_flagstd::call_once用于确保某个函数或代码块只被执行一次,即使在多线程环境中。
#include <mutex>

std::once_flag once_flag;
void (*init_func)() = nullptr;

void init() {
    // 初始化代码
}

void do_init() {
    std::call_once(once_flag, init);
}

三、注意事项

  • 避免死锁:确保所有线程获取锁的顺序一致,或者使用try_lock来尝试获取锁。
  • 避免活锁:确保线程在等待锁时能够响应其他线程释放锁的信号。
  • 锁的粒度:尽量减小锁的范围,以提高性能。
  • 锁的持有时间:尽量减少锁持有的时间,以减少等待时间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CnLg.NJ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值