当前位置: 首页 > news >正文

C++ —— 线程同步(互斥锁)

C++ —— 线程同步(互斥锁)

  • 线程同步
  • 互斥锁(互斥量)
    • 测试代码
    • mutex互斥锁

线程同步

线程同步:多线程协同工作,协商如何使用共享资源。
C++11线程同步包含三部分内容:

  1. 互斥锁(互斥量)
  2. 条件变量
  3. 生产/消费者模型

互斥锁(互斥量)

只有加锁解锁两种状态,确保同一时间只有一个线程访问共享资源。
访问共享资源之前加锁,加锁成功访问资源,访问完成解锁释放。
若某线程持有锁,其他线程形成等待队列

C++11提供了4种互斥锁:

  • mutex:互斥锁(最常用)
  • timed_mutex:带超时机制的互斥锁
  • recursive_mutex:递归互斥锁
  • recursive_timed_mutex:带超时机制的递归互斥锁

测试代码

#include <iostream>
#include <thread>
using namespace std;

void func (int n, const string& s) {
    for (int i = 1; i <= 10; i++) {
        cout << "No." << i << ", n = " << n << ", s = " << s << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
}
a
int main () {
    thread t1(func, 1, "t1");
    thread t2(func, 2, "t2");
    thread t3(func, 3, "t3");
    thread t4(func, 4, "t4");
    thread t5(func, 5, "t5");
    thread t6(func, 6, "t6");

    t1.join();
    t2.join();
    t3.join();
    t4.join();
    t5.join();
    t6.join();

    return 0;
}

cout属于全局对象,若多线程都用它向屏幕输出文字,会出乱子。线程越多,越容易乱。

mutex互斥锁

使用互斥锁cout加锁,代码如下:

#include <iostream>
#include <thread>
#include <mutex> // 使用互斥锁需要包含的头文件
using namespace std;

mutex mtx; // 创建互斥锁对象,用于保护共享资源cout对象。

void func (int n, const string& s) {
    for (int i = 1; i <= 10; i++) {
        // 每次调用cout对象之前,申请加锁
        mtx.lock();
        cout << "No." << i << ", n = " << n << ", s = " << s << endl;
        // 用完了就解锁
        mtx.unlock();
        this_thread::sleep_for(chrono::seconds(1));
    }
}

int main () {
   // 代码不变...
}

再看一段示例代码:

#include <iostream>
#include <chrono> // 时间相关操作的头文件
#include <thread> // 线程相关操作的头文件
#include <mutex> // 互斥锁的头文件
using namespace std;

int a = 0;
mutex mtx; // 创建互斥锁对象,用于保护共享资源a变量。

void func () {
    for (int i = 0; i < 1000000; ++i) {
        mtx.lock();
        a++;
        mtx.unlock();
    }
}

int main () {
    auto start = chrono::steady_clock::now();
    thread t1(func);
    thread t2(func);

    t1.join();
    t2.join();
    auto end = chrono::steady_clock::now();
    cout << "time = " << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms" << endl;
    cout << "a = " << a << endl;

    return 0;
}

运行结果:

time = 101ms
a = 2000000

在代码中添加一些打印信息,能更清楚的观察到:两个线程申请加锁,只有一个成功,另外一个线程等待,直到第一个线程解锁后第二个线程才能加锁。

#include <iostream>
#include <chrono> // 时间相关操作的头文件
#include <thread> // 线程相关操作的头文件
#include <mutex> // 互斥锁的头文件
using namespace std;

int a = 0;
mutex mtx;

void func () {
    for (int i = 0; i < 1000000; ++i) {
        cout << "thread id: " << this_thread::get_id() << ", 申请加锁" << endl;
        mtx.lock();
        cout << "thread id: " << this_thread::get_id() << ", 加锁成功" << endl;
        a++;
        this_thread::sleep_for(chrono::seconds(5));
        mtx.unlock();
        cout << "thread id: " << this_thread::get_id() << ", 解锁" << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
}

int main () {
    thread t1(func);
    thread t2(func);

    t1.join();
    t2.join();
    
    cout << "a = " << a << endl;

    return 0;
}

运行结果:

thread id: 139727756003072, 申请加锁
thread id: 139727756003072, 加锁成功
thread id: 139727747610368, 申请加锁
thread id: 139727756003072, 解锁
thread id: 139727747610368, 加锁成功
thread id: 139727756003072, 申请加锁
thread id: 139727747610368, 解锁

感谢浏览


文章转载自:

http://V6Lkqz2P.wyLpy.cn
http://Uolqse6z.wyLpy.cn
http://b1MVidKh.wyLpy.cn
http://SZFsenp0.wyLpy.cn
http://5Qp7e0Y1.wyLpy.cn
http://fhjEaOvx.wyLpy.cn
http://vXVCgvuc.wyLpy.cn
http://ze6far2r.wyLpy.cn
http://jQZaSeZt.wyLpy.cn
http://S9Vhv8SD.wyLpy.cn
http://Yd0YFlDU.wyLpy.cn
http://uF0g0R9k.wyLpy.cn
http://JPxgetlq.wyLpy.cn
http://6Y33vb7G.wyLpy.cn
http://ciJY1KoA.wyLpy.cn
http://5Eri10Zs.wyLpy.cn
http://nJGqzB8v.wyLpy.cn
http://4axmrzbl.wyLpy.cn
http://JCMpUoJ4.wyLpy.cn
http://Z9T3FXzy.wyLpy.cn
http://Mzbz5msP.wyLpy.cn
http://k7vIFwfw.wyLpy.cn
http://RdwkWBNx.wyLpy.cn
http://SLx6CfOZ.wyLpy.cn
http://3Oegpk9j.wyLpy.cn
http://kqh58EPw.wyLpy.cn
http://6JSlkQkr.wyLpy.cn
http://te68VMgz.wyLpy.cn
http://zeF9ATiT.wyLpy.cn
http://GP64sJCt.wyLpy.cn
http://www.dtcms.com/a/77865.html

相关文章:

  • vue 中常用操作数组的方法
  • Minecraft命令总结(持续更新)
  • Deal - DbC、检查Python 值、异常和副作用
  • 鸿蒙NEXT项目实战-百得知识库03
  • jpa报错 Validation failed for query for method public abstract
  • MySQL单表查询
  • 练习题:94
  • MutableList 和 ArrayList 区别
  • 格力地产更名“珠免集团“ 全面转型免税赛道
  • 【AI绘画教程】从MJ到SD,九周精通AI绘画,MJ基础至SD模型训练全方位教学
  • 高级java每日一道面试题-2025年3月06日-微服务篇[Eureka篇]-Eureka Server和Eureka Client关系?
  • OpenWrt中使用GPIO模拟I2C控制CAT9555芯片的示例代码
  • 显示模组ESD损伤探讨
  • 调用百度智能云API实现货币识别
  • 蓝桥杯第九天 2022 省赛 第 4 题 最少刷题数
  • QtCreator16创建WebAssembly工程在浏览器中显示图片
  • MSys2统一开发环境,快速搭建windows opencv环境
  • 【Embedded World 2025:边缘 AI、存储革新与 1X nm 工艺重塑嵌入式未来】
  • AI大模型:(一)1.大模型的发展与局限
  • 学习threejs,构建THREE.ParametricGeometry参数化函数生成几何体
  • 逆向中常见的加密算法识别
  • Flutter 打包 ipa出现错误问题 exportArchive
  • 小红书不绑定手机号会显示ip吗
  • 实验11 机器学习-贝叶斯分类器
  • 【NCRE】2025计算机一级选择题真题题库(476道题目含答案(476/476))
  • 正点原子[第三期]Arm(iMX6U)Linux移植学习笔记-6.2uboot启动流程-lowlevel_init,s_init,_main函数执行
  • Docker安装,并pullMySQL和redis
  • 鸿蒙NEXT项目实战-百得知识库05
  • python字符级差异分析并生成 Word 报告 自然语言处理断句
  • Unity Shader Graph高级节点逻辑设计:程序化噪声生成技术详解