C++11 新特性:多线程支持 - 互斥锁

在多线程编程中,同步是一个至关重要的概念,它确保了程序在执行共享资源访问时的正确性和一致性。

锁(Locks)是实现线程同步的基本工具之一,C++11 在<mutex>头文件中提供了多种锁类型和相关操作。

下面我们将介绍 C++11 线程中的几种锁及其使用方法。

std::mutex

std::mutex是最基本的互斥锁,它提供了独占的锁定机制,确保同一时间只有一个线程可以访问被保护的资源。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 定义互斥量

void print_thread_id(int id) {
    mtx.lock(); // 上锁
    std::cout << "Thread #" << id << '\n';
    mtx.unlock(); // 解锁
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(print_thread_id, i + 1);

    for (auto& th : threads) th.join();
    return 0;
}

输出:

Thread #9
Thread #5
Thread #2
Thread #4
Thread #10
Thread #3
Thread #1

std::recursive_mutex

std::recursive_mutex允许同一个线程多次获得同一个互斥量。这对于递归函数访问被保护资源非常有用。

#include <iostream>
#include <thread>
#include <mutex>

std::recursive_mutex rec_mtx; // 定义可递归互斥量
int counter = 0;

void recursive_access(int id, int level) {
    rec_mtx.lock(); // 上锁
    if (level < 5) {
        std::cout << "Thread #" << id << ": level " << level << '\n';
        recursive_access(id, level + 1);
    }
    rec_mtx.unlock(); // 解锁
}

int main() {
    std::thread t1(recursive_access, 1, 0);
    std::thread t2(recursive_access, 2, 0);
    t1.join();
    t2.join();
    return 0;
}

输出:

Thread #1: level 3
Thread #1: level 4
Thread #2: level 0
Thread #2: level 1
Thread #2: level 2
Thread #2: level 3
Thread #2: level 4

std::lock_guard

std::lock_guard是一个作用域锁,提供了RAII(Resource Acquisition Is Initialization)风格的锁管理。它在构造时自动上锁,在析构时自动解锁,适用于简单的场景。

#include <iostream>
#include <thread>
#include <mutex>

std::mutex mtx; // 定义互斥量

void print_thread_id(int id) {
    std::lock_guard<std::mutex> lck(mtx); // 自动上锁
    std::cout << "Thread #" << id << '\n';
    // 自动解锁
}

int main() {
    std::thread threads[10];
    for (int i = 0; i < 10; ++i)
        threads[i] = std::thread(print_thread_id, i + 1);

    for (auto& th : threads) th.join();
    return 0;
}

输出:

Thread #7
Thread #8
Thread #9
Thread #10
Thread #1
Thread #3
Thread #6

std::unique_lock

std::unique_lock是一种更灵活的锁,与std::lock_guard类似,也提供RAII风格的锁管理,但它允许延迟锁定(deferred locking)、提前解锁(unlocking before the end of the scope)、以及通过条件变量等待(waiting on condition variables)。

#include <iostream>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <thread>
#include <vector>

std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;

void producer(int id) {
    int data = id * 42; // 简单地使用id乘以42作为数据
    {
        std::unique_lock<std::mutex> lck(mtx);
        data_queue.push(data);
        std::cout << "Producer " << id << " added " << data << " to queue\n";
        cv.notify_one(); // 通知等待的消费者线程
    }
}

void consumer(int id) {
    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck, []{ return !data_queue.empty(); }); // 等待直到data_queue非空
    int data = data_queue.front();
    data_queue.pop();
    std::cout << "Consumer " << id << " processed " << data << std::endl;
}

int main() {
    std::vector<std::thread> producers;
    std::vector<std::thread> consumers;

    // 创建生产者线程
    for (int i = 0; i < 5; ++i) {
        producers.push_back(std::thread(producer, i + 1));
    }

    // 创建消费者线程
    for (int i = 0; i < 5; ++i) {
        consumers.push_back(std::thread(consumer, i + 1));
    }

    // 等待所有生产者线程完成
    for (auto& t : producers) {
        t.join();
    }

    // 等待所有消费者线程完成
    for (auto& t : consumers) {
        t.join();
    }

    return 0;
}

输出:

Producer 5 added 210 to queue
Consumer 2 processed 210
Producer 1 added 42 to queue
Consumer 1 processed 42
Producer 4 added 168 to queue
Consumer 4 processed 168
Producer 3 added 126 to queue
Consumer 5 processed 126
Producer 2 added 84 to queue
Consumer 3 processed 84

总结

C++11 的多线程库为开发者提供的线程同步工具,包括各种类型的锁。今天介绍的是最简单、最常用的互斥锁,最后一个示例用到了条件变量和它的通知机制,这个我后面文章会介绍其用法。

通过上述示例,我们可以看到如何在实际编程中利用这些锁来保护共享数据,避免数据竞争和死锁等问题,确保程序的正确性和稳定性。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值