C++笔记 - 锁

193 阅读1分钟

在多线程编程中被广泛使用,通过能够保证临界区的数据顺序访问。在使用的过程中,最容易现的问题是:死锁。幸好C++为我们提供了很好的机制尽量避免死锁的出现。


std::lock_guard 是一个RAII风格的锁,在离开作用域范围时,自动释放锁。下面直接看一个例子:

#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
#include <cassert>

static int g_index = 0;
static const int CNT = 1000;
std::mutex g_mutex;

static void _inc(void) {
    for (int i = 0; i < CNT; i++) {
        const std::lock_guard<std::mutex> lock(g_mutex);
        ++g_index;
    }
}

int main(void) {
    std::vector<std::thread> v_th;

    for (int i = 0; i < 10; i++) {
        std::thread t(_inc);
        v_th.push_back(std::move(t));
    }

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

    assert(g_index == 1000 * 10);
    return 0;
}

std::unique_lock是一个功能更全的。支持延迟锁,时间锁,互斥锁,递归锁,还能支持转移的所有权等功能。下面也看一个例子:

#include <cassert>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

static const int CNT = 1000;
static int g_inc_index = 0;
static int g_dec_index = 0;
std::mutex g_inc_mutex;
std::mutex g_dec_mutex;

static void _run(void) {
    for (int i = 0; i < CNT; i++) {
        std::unique_lock<std::mutex> inc_lock(g_inc_mutex, std::defer_lock);
        std::unique_lock<std::mutex> dec_lock(g_dec_mutex, std::defer_lock);

        std::lock(inc_lock, dec_lock);
        ++g_inc_index;
        --g_dec_index;
    }
}

int main(void) {
    std::vector<std::thread> v_th;

    for (int i = 0; i < 10; i++) {
        v_th.emplace_back(_run);
    }

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

    assert(g_inc_index == -g_dec_index);
    return 0;
}

std::scoped_lockstd::lock_guard类似,不同的是能够同时获取多个。下面看一个例子:

#include <cassert>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>

static int g_inc_index = 0;
static int g_dec_index = 0;
std::mutex g_inc_mutex;
std::mutex g_dec_mutex;

static void _run(const int count) {
    for (int i = 0; i < count; i++) {
        std::scoped_lock lock(g_inc_mutex, g_dec_mutex);
        ++g_inc_index;
        --g_dec_index;
    }
}

int main(void) {
    std::vector<std::thread> v_th;
    const int count = 1000;

    for (int i = 0; i < 10; i++) {
        v_th.emplace_back(_run, count);
    }

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

    assert(g_inc_index == -g_dec_index);
    return 0;
}

参考: