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_; // 在锁保护下读取
}