C++11各种锁的具体使用

C++11各种锁的具体使用

在多线程编程时,锁是常用的线程同步机制之一。C++11中提供了多种不同的锁类型,用于处理不同的并发情况,本文将详细介绍这些锁的用法。

1、互斥锁(std::mutex

使用互斥锁可以实现对共享资源的互斥访问。

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

std::mutex mtx; //定义互斥锁对象

void func(int id)
{
    for(int i = 0; i < 5; ++i)
    {
        mtx.lock(); //获取互斥锁
        std::cout << "Thread " << id << " : " << i << std::endl;
        mtx.unlock(); //释放互斥锁
    }
}

int main()
{
    std::vector<std::thread> ths;
    for(int i = 1; i <= 5; ++i)
    {
        ths.emplace_back(func, i);
    }

    for(auto& th : ths)
    {
        th.join();
    }

    return 0;
}

输出:

Thread 1 : 0
Thread 1 : 1
Thread 1 : 2
Thread 1 : 3
Thread 1 : 4
Thread 3 : 0
Thread 3 : 1
Thread 3 : 2
Thread 3 : 3
Thread 3 : 4
Thread 2 : 0
Thread 2 : 1
Thread 2 : 2
Thread 2 : 3
Thread 2 : 4
Thread 4 : 0
Thread 4 : 1
Thread 4 : 2
Thread 4 : 3
Thread 4 : 4
Thread 5 : 0
Thread 5 : 1
Thread 5 : 2
Thread 5 : 3
Thread 5 : 4

在函数func中,使用互斥锁对cout流实现了互斥访问,从而避免线程之间的竞争。

2、递归互斥锁(std::recursive_mutex

递归互斥锁和普通互斥锁一样,它也可以保证对共享资源的互斥访问,但它允许同一线程多次获取互斥锁而不会死锁。

#include <iostream>
#include <mutex>
#include <vector>

std::recursive_mutex rmtx;

int recur(int n)
{
    if(n <= 1)
        return 1;
    rmtx.lock();
    int ret = n * recur(n - 1);
    rmtx.unlock();
    return ret;
}

int main()
{
    std::vector<std::thread> ths;
    for(int i = 1; i <= 5; ++i)
    {
        ths.emplace_back([i](){
            std::cout << "Thread " << i << ": " << recur(5) << std::endl;
        });
    }

    for(auto& th : ths)
    {
        th.join();
    }

    return 0;
}

输出:

Thread 1: 120
Thread 2: 120
Thread 3: 120
Thread 4: 120
Thread 5: 120

在递归函数recur中,使用了递归互斥锁,允许同一线程多次获取互斥锁。

3、共享锁(std::shared_mutex

共享锁用于读写分离场景,多个线程可以同时持有共享锁(共享访问),但只有一个线程可以持有独占锁(排它访问)。

#include <iostream>
#include <shared_mutex>
#include <thread>
#include <vector>

std::shared_mutex smtx;

void read_func(int id)
{
    smtx.lock_shared();
    std::cout << "Thread " << id << ": read" << std::endl;
    smtx.unlock_shared();
}

void write_func(int id)
{
    smtx.lock();
    std::cout << "Thread " << id << ": write" << std::endl;
    smtx.unlock();
}

int main()
{
    std::vector<std::thread> ths;
    for(int i = 1; i <= 5; ++i)
    {
        if(i % 2 == 0)
            ths.emplace_back(write_func, i);
        else
            ths.emplace_back(read_func, i);
    }

    for(auto& th : ths)
    {
        th.join();
    }

    return 0;
}

输出:

Thread 1: read
Thread 3: read
Thread 5: read
Thread 2: write
Thread 4: write

在函数read_func中,使用共享锁对cout流实现了共享访问,在函数write_func中,使用共享锁对cout流实现了排它访问。

4、条件变量锁(std::condition_variable

条件变量锁允许一个线程等待另一个线程满足特定条件时被唤醒。

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

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

void func1()
{
    std::unique_lock<std::mutex> lock(mtx);
    std::cout << "func1 start" << std::endl;
    flag = true;
    lock.unlock();
    cv.notify_one();
}

void func2()
{
    std::unique_lock<std::mutex> lock(mtx);
    while(!flag)
    {
        cv.wait(lock); //等待条件变量
    }
    std::cout << "func2 start" << std::endl;
}

int main()
{
    std::thread t1(func1);
    std::thread t2(func2);
    t1.join();
    t2.join();

    return 0;
}

输出:

func1 start
func2 start

在函数func1中,改变了全局变量flag的值,并使用了条件变量通知线程func2,从而被唤醒。

以上就是C++11各种锁的详细介绍及对应的示例代码。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++11各种锁的具体使用 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • C语言函数封装及变量的作用域

    C语言函数封装及变量的作用域 函数封装 函数封装是指将一段代码打包成函数作为一个单元,使得代码可重用并能提高代码的可读性。在C语言中,可以使用函数的方式实现对代码的封装。 函数的定义与调用 函数的定义分为两步:函数声明和函数实现。 函数声明通常放在头文件中,用于告诉编译器函数的存在,并告知该函数的参数及返回值类型;函数实现则放在源文件中,实现函数的具体功能。…

    C 2023年5月22日
    00
  • Win11C盘空间不足怎么扩容?Win11给C盘扩容的方法

    Win11C盘空间不足怎么扩容?Win11给C盘扩容的方法,步骤如下: 操作前提 在进行操作之前,需要保证以下内容: 有一个可用的U盘或移动硬盘。 下载Windows系统的安装文件。 准备好备份重要数据的位置。 注:扩容C盘过程会涉及到更改系统分区的操作,有一定风险,如有不熟悉操作的风险,请在操作前进行备份数据以备万一。 步骤一:备份数据 在进行分区扩容之前…

    C 2023年5月23日
    00
  • c++代码各种注释示例详解

    C++代码注释详解 C++代码注释是一种为程序添加额外说明、解释和提示的方式,它有助于程序的可读性和可维护性。 本文将详细讲解C++代码各种注释示例及说明。 单行注释 单行注释以//开始,直到该行结束,可用于简单的注释或激活/屏蔽代码。 示例: int a = 5; // 定义变量a,赋值为5 // int b = 10; // 激活该行会定义变量b,赋值为…

    C 2023年5月23日
    00
  • 终于把淘宝SEO相关概念讲明白了 淘宝常用名词解读

    终于把淘宝SEO相关概念讲明白了 淘宝常用名词解读 什么是淘宝SEO? 淘宝SEO是指通过淘宝搜索引擎优化技术,提升淘宝店铺和商品在淘宝内部搜索结果页的排名,增加店铺和商品的曝光率和销售额的过程。 在实际操作中,淘宝SEO主要包括优化关键词、优化描述、提高转化率等方面。通过细节优化,使得店铺和商品更符合用户搜索习惯和需求。 淘宝常用名词解读 1. 关键词 关…

    C 2023年5月22日
    00
  • C#中使用SQLite数据库的方法介绍

    C#中使用SQLite数据库的方法介绍 什么是SQLite数据库? SQLite是一个轻量级的、开源的、关系型数据库管理系统(RDBMS)。 它包括C库、命令行工具和多种语言的API,主要使用在嵌入式设备和小型应用程序中。 SQLite不需要单独的服务器进程或者操作系统的支持,因为SQLite直接在应用程序中存储数据。 在C#中使用SQLite数据库的方法 …

    C 2023年5月22日
    00
  • OpenCV mask的作用及如何制作掩模mask

    OpenCV的mask是一个二进制图像,用于控制对另一个图像的操作。在图像处理中,掩模通常被用于选择感兴趣区域(ROI)或执行像素级别的操作,如图像增强、滤波、混合等。 制作掩模实际上就是创建一个二值图像,其中像素值为0或255(黑或白),作用是将掩模图像中为255的像素区域与原图像中对应位置的像素进行操作,在区域内进行所需的图像处理操作。 下面我们以制作掩…

    C 2023年5月23日
    00
  • C++AVL树4种旋转详讲(左单旋、右单旋、左右双旋、右左双旋)

    C++AVL树4种旋转详讲 什么是AVL树? AVL树是一种自平衡二叉搜索树,它在插入或删除一个节点时,会通过旋转操作进行自平衡。AVL树的特点是保证树的高度始终保持在O(logN)的水平,从而保证了树的查询、插入、删除等操作时间复杂度保持在O(logN)的水平。因此在大规模数据的场景下,使用AVL树能够取得很好的性能表现。 AVL树的基本操作 AVL树的基…

    C 2023年5月22日
    00
  • C++代码实现贪吃蛇小游戏

    C++代码实现贪吃蛇小游戏的完整攻略 介绍 贪吃蛇是一种经典的游戏,也是C++学习过程中的一个很好的项目。本文将介绍如何使用C++实现一个简单的贪吃蛇小游戏。 前置知识 本文需要读者具备C++的基础知识,以及对标准库函数和数据结构的理解。 程序设计思路 贪吃蛇游戏的设计思路如下: 绘制游戏界面:使用控制台绘制游戏界面,包括蛇、食物和地图等。 控制蛇的移动:根…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部