两线程同步问题:消除C26110警告及无手动Mutex实现
线程同步问题:Pipeline初始化完成后创建Connection
问题1:C26110警告的含义
C26110是微软静态代码分析工具抛出的警告,核心含义是:当前线程在调用std::_Mutex_base::unlock时,并没有持有该mutex的锁。
看你的代码逻辑:
- main函数中先调用
m.lock()持有锁 - pipeline_func中调用
m.unlock()释放锁,此时mutex已经处于未锁定状态 - main函数最后又调用
m.unlock(),这时候当前线程(main线程)并没有持有这个mutex的锁,触发了该警告。
另外,mutex的lock和unlock必须严格成对出现,你的代码中一次lock对应两次unlock,本身就是不符合mutex使用规范的错误操作。
问题2:改写代码避免手动操作mutex
手动操作mutex容易出现锁未持有就解锁、锁泄漏等问题,推荐用条件变量(std::condition_variable)或者std::promise/std::future来实现这种一次性的线程同步逻辑,以下是两种可行方案:
方案1:使用条件变量(适合复杂同步场景)
#include <iostream> #include <mutex> #include <condition_variable> #include <thread> using namespace std::chrono_literals; class Pipeline { public: Pipeline() { std::cout << "Pipeline()\n"; }; void init() { std::cout << "Pipeline::init()\n"; std::this_thread::sleep_for(3s); }; void run() { while (true) { std::cout << "Pipeline::run()\n"; std::this_thread::sleep_for(1s); } }; }; class Connection { public: Connection(Pipeline* p) { std::cout << "Connection()\n"; }; void run() { while (true) { std::cout << "Connection::run()\n"; std::this_thread::sleep_for(1s); } }; }; void pipeline_func(Pipeline** pipeline, std::mutex& m, std::condition_variable& cv, bool& is_pipeline_ready) { *pipeline = new Pipeline(); (*pipeline)->init(); // 标记Pipeline就绪并通知等待线程 { std::lock_guard<std::mutex> lock(m); is_pipeline_ready = true; } cv.notify_one(); (*pipeline)->run(); // 无限运行 }; void connection_func(Pipeline** pipeline, std::mutex& m, std::condition_variable& cv, bool& is_pipeline_ready) { // 等待Pipeline初始化完成,自动管理锁的状态 std::unique_lock<std::mutex> lock(m); cv.wait(lock, [&is_pipeline_ready](){ return is_pipeline_ready; }); Connection connection(*pipeline); connection.run(); // 无限运行 }; int main() { Pipeline* pipeline = nullptr; std::mutex m; std::condition_variable cv; bool is_pipeline_ready = false; std::thread pipelineTh(pipeline_func, &pipeline, std::ref(m), std::ref(cv), std::ref(is_pipeline_ready)); std::thread connectionTh(connection_func, &pipeline, std::ref(m), std::ref(cv), std::ref(is_pipeline_ready)); pipelineTh.join(); connectionTh.join(); }
方案2:使用std::promise/std::future(适合一次性结果传递)
#include <iostream> #include <thread> #include <future> using namespace std::chrono_literals; class Pipeline { public: Pipeline() { std::cout << "Pipeline()\n"; }; void init() { std::cout << "Pipeline::init()\n"; std::this_thread::sleep_for(3s); }; void run() { while (true) { std::cout << "Pipeline::run()\n"; std::this_thread::sleep_for(1s); } }; }; class Connection { public: Connection(Pipeline* p) { std::cout << "Connection()\n"; }; void run() { while (true) { std::cout << "Connection::run()\n"; std::this_thread::sleep_for(1s); } }; }; void pipeline_func(Pipeline** pipeline, std::promise<Pipeline*>& prom) { *pipeline = new Pipeline(); (*pipeline)->init(); prom.set_value(*pipeline); // 传递初始化完成的Pipeline指针 (*pipeline)->run(); // 无限运行 }; void connection_func(std::future<Pipeline*>& fut) { Pipeline* pipeline = fut.get(); // 等待Pipeline初始化完成,自动同步 Connection connection(pipeline); connection.run(); // 无限运行 }; int main() { Pipeline* pipeline = nullptr; std::promise<Pipeline*> prom; std::future<Pipeline*> fut = prom.get_future(); std::thread pipelineTh(pipeline_func, &pipeline, std::ref(prom)); std::thread connectionTh(connection_func, std::ref(fut)); pipelineTh.join(); connectionTh.join(); }
改写思路说明
两种方案都遵循RAII原则,完全避免手动调用lock/unlock:
- 条件变量方案通过
std::lock_guard和std::unique_lock自动管理锁的生命周期,wait方法会在等待期间自动释放锁、被唤醒后重新获取锁 - promise/future方案更简洁,内部封装了同步逻辑,仅需通过
set_value和get完成线程间的结果传递与等待
内容的提问来源于stack exchange,提问作者yalov
相关产品推荐
相关产品推荐

