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

C++ 互斥锁、条件变量的基础使用

前言

在C++多线程开发中,互斥锁和条件变量是线程同步中非常重要的部分。互斥锁和条件变量主要用于确保对共享资源的访问是线程安全的(C++的容器都不是线程安全的)。本文主要介绍互斥锁和条件变量的基础使用。

互斥锁(Mutex)

互斥锁用于保护共享数据,防止多个线程同时修改同一资源;
当在多线程场景时,某一线程访问某一个被互斥锁保护的资源时,线程会首先尝试获取该互斥锁的所有权,但是如果锁已经被其他线程获取所有权,则该线程会被阻塞,直到其他线程放弃锁的所有权。
在C++中,<mutex>头文件提供了std::mutex

示例代码

#include <mutex> 
#include <thread> 
std::mutex mtx; // 创建一个互斥锁 
void func() 
{ mtx.lock(); // 尝试获取锁 // 访问或修改共享资源 mtx.unlock(); // 释放锁 
} // 或者使用std::lock_guard简化锁的获取与释放 
void func_with_guard() 
{ std::lock_guard<std::mutex> lock(mtx); // 构造时自动获取锁,析构时自动释放锁 // 访问或修改共享资源 
}

条件变量(Condition Variable)

条件变量主要与互斥锁配合使用,能够将线程在某一条件不满足时,使其挂起,并在条件满足时唤醒;
在C++中,<condition_variable>头文件提供了

  • std::condition_variable
  • std::condition_variable_any
    两者对比,后者相对前者更灵活,但是性能相对差一点;

示例代码

#include <mutex>
#include <condition_variable>
#include <thread> std::mutex mtx; 
std::condition_variable cv; 
bool ready = false; void print_id(int id) 
{ std::unique_lock<std::mutex> lck(mtx); while (!ready) {cv.wait(lck); // 等待ready变为true }// 当ready为true时,继续执行... std::cout << "Thread " << id << '\n'; 
} void go() 
{ std::unique_lock<std::mutex> lck(mtx); ready = true; cv.notify_all(); // 唤醒所有等待的线程 
} int main() 
{ std::thread threads[10]; // 创建10个线程 for (int i=0; i<10; ++i) {threads[i] = std::thread(print_id, i);} std::cout << "10 threads ready to race...\n";go(); // 唤醒所有线程 // 等待所有线程完成 for (auto& th : threads) {th.join(); return 0; }
}

条件变量相关函数

线程阻塞wait

基本形式:

void wait(std::unique_lock<std::mutex>& lock);

wait函数接受一个unique_lock<std::mutex>类型的引用作为参数;调用wait函数时,当前线程会释放被 unique_lock<std::mutex>占用的锁并让线程阻塞,直到被另一个线程唤醒;

线程唤醒

notify_one
void notify_all() noexcept;

唤醒在条件变量上等待队列中的第一个线程;
(如果队列为空,不会有任何效果)

notify_all
void notify_one() noexcept;

唤醒等待队列中的所有线程;

相同点

当线程被唤醒时,会尝试获取与条件变量相关联的互斥锁。然而,由于只有一个线程能在任何给定时间持有锁,因此只有一个线程会成功获取锁并从wait函数中返回。未成功获取锁的线程将重新进入等待状态,直到锁被释放并再次尝试获取。


http://www.mrgr.cn/news/24784.html

相关文章:

  • 初始Linux 和 各种常见指令
  • 杀毒软件 | Malware Hunter v1.189.0.816 绿色版
  • 算法知识点————背包问题【动态规划】【打家劫舍】
  • 文件IO编程
  • 鸿蒙交互事件开发04——手势事件
  • 从头开始嵌入式第三十八天(数据结构 双向链表)
  • C:字符函数与字符串函数-学习笔记
  • 继图书管理项目遗留的问题修改
  • 谷歌账号登录的时候需要手机验证,但是验证的手机号码已经注销了怎么办?
  • 思维导图神器!四款高效工具助你职场逆袭
  • 【c++】类和对象详解
  • 网络编程day05(循环服务器、并发服务器)
  • Vue3+TS项目pinia使用优化在stores目录下新建index.ts
  • GEE 将本地 GeoJSON 文件上传到谷歌资产
  • 异步编程的实现方式
  • #include <netinet/in.h>
  • Reduce:一款开源的短网址平台!!【送源码】
  • 虚幻引擎 | (类恐鬼症)玩家和NPC语音聊天
  • 【C++】C++ 多态的底层实现原理
  • Window 本地启动Nacos