当前位置: 首页 > 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.xdnf.cn/news/1235251.html

相关文章:

  • [硬件电路-148]:数字电路 - 什么是CMOS电平、TTL电平?还有哪些其他电平标准?发展历史?
  • 本地环境vue与springboot联调
  • 2025年6月电子学会青少年软件编程(C语言)等级考试试卷(四级)
  • [硬件电路-143]:模拟电路 - 开关电源与线性稳压电源的详细比较
  • Ubuntu22.4部署大模型前置安装
  • webrtc弱网-QualityScaler 源码分析与算法原理
  • ubuntu apt安装与dpkg安装相互之间的关系
  • (一)全栈(react配置/https支持/useState多组件传递/表单提交/React Query/axois封装/Router)
  • 自动驾驶中的传感器技术18——Camera(9)
  • GitLab 代码管理平台部署及使用
  • Java基本技术讲解
  • PPT自动化 python-pptx - 9: 图表(chart)
  • 决策树学习全解析:从理论到实战
  • 【LeetCode刷题指南】--二叉树的后序遍历,二叉树遍历
  • PPT写作五个境界--仅供学习交流使用
  • 【1】WPF界面开发入门—— 图书馆程序:登录界面设计
  • 业务系统跳转Nacos免登录方案实践
  • web前端React和Vue框架与库安全实践
  • 【设计模式】4.装饰器模式
  • ThinkPHP5x,struts2等框架靶场复现
  • LLM - 智能体工作流设计模式
  • 【嵌入式硬件实例】-555定时器IC的负电压发生器
  • 设计原则和设计模式
  • 【C++ 初级工程师面试--4】形参带默认值的函数,特点,效率,注意事项
  • 秋招笔记-8.3
  • PHP面向对象编程与数据库操作完全指南-下
  • C语言数据结构(7)贪吃蛇项目2.贪吃蛇项目实现
  • 云轴科技ZStack AI翻译平台建设实践-聚焦中英
  • React中的Hooks
  • JavaEE初阶第十三期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(十一)