类内函数中std::mutex在多线程调用时同步失效问题
类内std::mutex无法实现线程同步的原因分析
问题现象
调用ThreadLessons类的func函数时,输出的Number 1、2、3混乱无序,未达到std::mutex预期的同步效果;但使用全局std::mutex的func函数输出的Number 4、5、6则完全有序。预期通过mutex保护共享资源std::cout,实现线程安全的输出。
相关代码
#include <thread> #include <iostream> #include <mutex> class ThreadLessons { private: std::mutex _threading_mutex_in_class; public: ThreadLessons() {} ThreadLessons(const ThreadLessons &tl) {} ThreadLessons operator=(const ThreadLessons &tl) {return *this;} void func(std::string s) { std::unique_lock lg(_threading_mutex_in_class); std::cout << std::endl; for(int i{0}; i<10; i++) { std::cout << s << std::endl; } } }; std::mutex _threading_mutex; void func(std::string s) { std::unique_lock lg(_threading_mutex); std::cout << std::endl; for(int i{0}; i<10; i++) { std::cout << s << std::endl; } } int main() { std::cout << "Starting threading of function from another class in same file" << std::endl; ThreadLessons t; std::thread t1(&ThreadLessons::func, t, "Number 1"); std::thread t2(&ThreadLessons::func, t, "Number 2"); std::thread t3(&ThreadLessons::func, t, "Number 3"); t1.join(); t2.join(); t3.join(); std::cout << "Starting threading of function from main" << std::endl; std::thread t4(func, "Number 4"); std::thread t5(func, "Number 5"); std::thread t6(func, "Number 6"); t4.join(); t5.join(); t6.join(); return 0; }
运行输出
Starting threading of function from another class in same file Number 1 Number 1 Number 1 Number 2 Number 2 Number 2 Number 3 Number 3 Number 1Number 2 Number 2 Number 3 Number 3Number 1 Number 2 Number 1Number 3Number 2 Number 2 Number 3 Number 3 Number 1 Number 1 Number 2 Number 1Number 3 Number 2 Number 1 Number 3 Number 3 Starting threading of function from main Number 4 Number 4 Number 4 Number 4 Number 4 Number 4 Number 4 Number 4 Number 4 Number 4 Number 5 Number 5 Number 5 Number 5 Number 5 Number 5 Number 5 Number 5 Number 5 Number 5 Number 6 Number 6 Number 6 Number 6 Number 6 Number 6 Number 6 Number 6 Number 6 Number 6
问题根源
创建线程时,std::thread t1(&ThreadLessons::func, t, "Number 1")中的t是值传递,std::thread会自动复制这个对象,导致t1、t2、t3各自持有一个独立的ThreadLessons实例。每个实例都拥有自己的_threading_mutex_in_class,相当于每个线程用自己的锁,完全起不到互斥作用,自然无法同步输出。
而全局的_threading_mutex是唯一的,所有线程都争抢这同一个锁,同一时间只有一个线程能操作std::cout,因此输出有序。
修复方案
有两种常用的修复方式:
1. 传递对象引用给线程
创建线程时使用std::ref(t)传递原对象的引用,让三个线程共享同一个ThreadLessons实例,这样它们会使用同一个类内mutex:
std::thread t1(&ThreadLessons::func, std::ref(t), "Number 1"); std::thread t2(&ThreadLessons::func, std::ref(t), "Number 2"); std::thread t3(&ThreadLessons::func, std::ref(t), "Number 3");
2. 将类内mutex声明为static
把_threading_mutex_in_class改成静态成员,这样不管创建多少ThreadLessons对象,所有实例共享同一个mutex:
class ThreadLessons { private: static std::mutex _threading_mutex_in_class; // 声明为static public: // 其他成员函数不变 }; // 必须在类外定义静态成员 std::mutex ThreadLessons::_threading_mutex_in_class;
修改后,类内func的线程就能通过同一个mutex实现互斥,输出效果会和全局mutex的版本一致。
内容的提问来源于stack exchange,提问作者robot9
相关产品推荐
相关产品推荐

