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

C++中多线程和互斥锁的基本使用

C++中多线程和互斥锁的基本使用

  • C++中多线程的基本使用
    • 一、 使用普通函数创建线程
    • 二、 使用 Lambda 表达式创建线程(推荐)
    • 三、 典型语法案例汇总
      • 1. 捕获引用 + 修改主线程变量
      • 2. detach 创建“后台线程”
      • 3. 使用类成员函数创建线程
      • 4. 多线程 + 互斥锁保护共享资源
    • 四、 总结
  • C++中互斥锁的基本使用
    • 一、互斥锁的作用
    • 二、未使用互斥锁 vs 使用互斥锁
    • 三、总结对比
    • 四、数据竞争分析与解决:
      • 1. 未使用互斥锁时的错误表现:
      • 2. 问题原因分析
      • 3. 互斥锁同步

参考:
C++多线程学习详解
C++多线程详解(全网最全)
带你吃透C++互斥锁

C++中多线程的基本使用

一、 使用普通函数创建线程

#include <iostream>
#include <thread>void doWork(int x) {std::cout << "Working: " << x << std::endl;
}int main() {std::thread t(doWork, 42);  // 传入函数指针和参数t.join();                   // 等待线程完成return 0;
}

特点:

  • 简单直观,适合逻辑独立的函数;
  • 无法直接访问主线程局部变量(除非使用全局或传参);

二、 使用 Lambda 表达式创建线程(推荐)

#include <iostream>
#include <thread>int main() {int value = 10;std::thread t([value]() {std::cout << "Lambda thread running: " << value << std::endl;});t.join();return 0;
}

特点:

  • 可以捕获外部变量(按值或按引用);
  • 灵活、简洁,适合小函数或带状态逻辑;
  • 推荐用于现代 C++ 多线程编程;

变量捕获方式说明

[value]() { ... }       // 值捕获(只读)
[&value]() { ... }      // 引用捕获(可读写)
[=]() { ... }           // 捕获当前作用域所有变量的副本
[&]() { ... }           // 捕获所有变量的引用
[this]() { ... }        // 捕获 this 指针(常用于类内部)

三、 典型语法案例汇总

1. 捕获引用 + 修改主线程变量

#include <iostream>
#include <thread>int main() {int result = 0;std::thread t([&result]() {result = 100;});t.join();std::cout << "Result = " << result << std::endl;return 0;
}

2. detach 创建“后台线程”

#include <iostream>
#include <thread>
#include <chrono>int main() {std::thread t([]() {std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Background thread finished!" << std::endl;});t.detach();  // 不阻塞主线程std::cout << "Main thread exits quickly" << std::endl;return 0;
}

⚠ 使用 detach() 时要保证线程的生命周期和资源访问安全,防止访问已经被释放的变量。


3. 使用类成员函数创建线程

#include <iostream>
#include <thread>class Worker {
public:void run(int x) {std::cout << "Worker running: " << x << std::endl;}
};int main() {Worker w;std::thread t(&Worker::run, &w, 123);  // 对象地址 + 参数t.join();return 0;
}

4. 多线程 + 互斥锁保护共享资源

#include <iostream>
#include <thread>
#include <mutex>std::mutex mtx;void printSafe(int id) {std::lock_guard<std::mutex> lock(mtx);  // 自动加锁/解锁std::cout << "Thread ID: " << id << std::endl;
}int main() {std::thread t1(printSafe, 1);std::thread t2(printSafe, 2);t1.join();t2.join();return 0;
}

四、 总结

方法使用场景优点缺点
普通函数 + std::thread逻辑封装好、参数固定的线程任务简洁明了无法捕获外部变量
Lambda + std::thread动态逻辑、需要捕获状态的任务灵活、可访问外部变量、现代推荐不适合太长逻辑

C++中互斥锁的基本使用

一、互斥锁的作用

用于在多线程程序中保护共享资源,防止数据竞争(data race)

常见用法:

#include <mutex>std::mutex mtx;void threadFunc() {mtx.lock();         // 加锁// 临界区代码(访问共享资源)mtx.unlock();       // 解锁
}

更推荐的方式:使用 std::lock_guard

#include <mutex>std::mutex mtx;void threadFunc() {std::lock_guard<std::mutex> lock(mtx);  // 析构自动释放锁// 临界区代码
}

二、未使用互斥锁 vs 使用互斥锁

【未使用互斥锁的版本】(存在数据竞争)

#include <iostream>
#include <thread>int counter = 0;void add() {for (int i = 0; i < 100000; ++i) {counter++;  // 多线程同时修改,可能会出现数据竞争}
}int main() {std::thread t1(add);std::thread t2(add);t1.join();t2.join();std::cout << "Final counter (no mutex): " << counter << std::endl;return 0;
}

【使用互斥锁的版本】(避免数据竞争)

#include <iostream>
#include <thread>
#include <mutex>int counter = 0;
std::mutex mtx;void add() {for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(mtx);counter++;}
}int main() {std::thread t1(add);std::thread t2(add);t1.join();t2.join();std::cout << "Final counter (with mutex): " << counter << std::endl;return 0;
}

三、总结对比

项目未使用互斥锁使用互斥锁(std::mutex
线程安全否,可能发生数据竞争是,线程安全
运行结果不确定,可能小于理论值稳定,符合预期值
性能较快(无锁)稍慢(加锁释放有开销)
推荐使用场景多线程只读,无共享写有共享写访问时必须使用

四、数据竞争分析与解决:

1. 未使用互斥锁时的错误表现:

日志输出异常:

[ INFO] [1754040346.741811266]: has returned trajectory with 18446744059935218265 points
[ INFO] [1754040346.741849866]: Waypoint 0: pos(0.00, 0.00, 0.00), yaw=0.00
[ INFO] [1754040346.741897766]: Waypoint 1: pos(0.00, 0.00, 0.00), yaw=0.00
...
[ INFO] [1754040346.752095449]: Waypoint 198: pos(0.00, 1385839276081958023820612523912152498000590369501888262879377677457232831957974476045551661306264153665361036034313791385840336402935561101059297341547615728513508795440121964374800002716729465953814831774142238856052736.00, 93166380607490246256839516428781872302764913110062132309905673477052295654788485977494611625942385485525609127354754662271381274992469689153543502627653304785958304676908077889204905930400618944397312.00), yaw=1012484461684370672638642220875319969585287415698854255336934621478697955025548036753087232028352492273457411087994188586700792

飞行行为异常:

  • 轨迹点数据出现极其巨大的无意义数值

  • 系统不稳定,可能出现崩溃

2. 问题原因分析

  • 写操作:后台线程在Decision()中更新latest_predict_state_

  • 读操作:主线程在StateGet()中读取latest_predict_state_

  • 无同步机制:两个线程同时访问同一块内存,导致数据损坏

当两个线程同时访问时:

  • 一个线程正在写入vector的大小信息

  • 另一个线程同时读取,可能读取到部分写入的数据

  • 导致vector的size字段被破坏,显示为SIZE_MAX

3. 互斥锁同步

修改前(无保护):

// 头文件
class Search {
private:std::vector<State> latest_predict_state_;
};// 写入操作
void Search::Decision(...) {latest_predict_state_ = execute(); // 直接写入,无保护
}// 读取操作
std::vector<State> Search::StateGet() {return latest_predict_state_; // 直接读取,无保护
}

修改后(有保护):

// 头文件
#include <mutex>class Search {
private:std::vector<State> latest_predict_state_;mutable std::mutex latest_predict_state_mutex_; // 添加互斥锁
};// 写入操作
void Search::Decision(...) {std::vector<State> new_trajectory = execute();// 在锁保护下更新共享数据{std::lock_guard<std::mutex> lock(latest_predict_state_mutex_);latest_predict_state_ = new_trajectory;}
}// 读取操作
std::vector<PredictState> Search::StateGet() {std::lock_guard<std::mutex> lock(latest_predict_state_mutex_);return latest_predict_state_; // 在锁保护下读取
}
http://www.dtcms.com/a/313210.html

相关文章:

  • 【RH124 问答题】第 8 章 监控和管理 Linux 进程
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现实时食物水果的检测识别(C#代码UI界面版)
  • 使用 Spring Initializr 生成项目结构:Java 开发效率提升指南
  • 【QT】常⽤控件详解(二)windowOpacitycursorfontsetToolTipfocusPolicystyleSheet
  • 大语言模型涉及的一些概念(持续更新)
  • VisualStudio的一些开发经验
  • 思二勋:数字资产化与资产数权化是RWA运作的核心逻辑
  • AtCoder Beginner Contest 417
  • MySQL事务与存储引擎的学习(一)
  • Docker国内镜像列表
  • Effective C++ 条款19: 设计class犹如设计type
  • Python从入门到精通计划Day02: Python语法探秘:当现代艺术遇到古典音乐
  • 最小半径覆盖问题【C++解法+二分+扫描线】
  • 【CF】Day118——杂题 (随机哈希 / 思维 | 贪心 / DP | 位运算构造 | 状态压缩 + 建图 + 最短路 | 构造 | 贪心)
  • 使用纯Docker命令搭建多服务环境(Linux版)
  • Python篇---包
  • 在Ansys Mechanical中对磨损进行建模
  • 力扣经典算法篇-40-螺旋矩阵(方向遍历:方向数组+已访问元素集合)
  • 【ROS2】常用命令
  • 04.Redis 的多实例
  • 双八无碳小车设计【16张cad】三维图+设计说明书
  • 【C++ 初级工程师面试--5】inline内联函数特点 、和普通函数的区别、什么时候适合内联?
  • json-server 快速搭建本地 Mock 数据服务
  • Day23--回溯--39. 组合总和,40. 组合总和 II,131. 分割回文串
  • Android 之 MVC架构
  • 线段树学习笔记 - 摩尔投票问题
  • I2C基础
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
  • PHP现代化全栈开发:前后端分离与API架构实践
  • uni-app学习笔记01-项目初始化及相关文件