|
// 问题抛出:多线程的坑,使用了共享变量
// http://www.ai111.vip/thread-1242-1-1.html
//解决1、三个线程共享了资源,把共享去掉即可 比较高效与简单的方法
//如果可能,必须要用的方法 不使用共享变量就可以了 多定义一下变量即可啊 最后汇总
// 原则:如果没有必要,线程间不要共享资源
//解决2:如果一定要使用共享变量呢?咋办? 从共享变量作文章 原子操作atomic
//std::atomic<int>
// http://www.ai111.vip/thread-1245-1-1.html
//还是会有问题:变量都是原子操作的变量,但是如果多个组合起来又未必是原子操作了!
//多线程共享变量解决3:锁mutex临界区
//解决3:如何正确的使用mutex?
//很容易用错 不把临界区暴露给使用者 而是在共享变量类内部用mutex进行保护
// mutable std::mutex m_mutex; 应该是一个mutable变量
// 容易出错点:1、忘记成对出现 2、重复调lock() 3、抛异常后无法调用unlock()了
// 调用了lock()一定要调用unlock() 联想到了 构造与析构函数 单独将mutex封装为一个Lock()类
// stl里有一个Lock()类的实现 std::lock_guard<std::mutex> lock(m_mutex);
// 还是会有bug:1、自己给自己转钱 2、一个线程里张三给李四转钱,另一个线程里李四给张三转钱
// 自己解决的思路:看张三与李四的 对象地址,按固定的顺序来加锁 估计stl底层实现也是这样的思路
// 真正的正确用法:在转钱函数里 void transfor_money(UserAccount& 张三,UserAccount& 李四, int money);
// std::lock("所有UserAccount对象的mutex都锁住")
// std::lock_gurad<std::mutex> lockA(a.mutex, std::adopt_lock); adopt_lock表示:构造不锁了 析构解锁
- #include <iostream>
- //#include <boost/thread/thread.hpp>
- #include <thread>
- #include <vector>
- //#include <atomic>
- #include <mutex>
- class Counter{
- public:
- Counter() : m_count(0) {}
- void addCount() {
- //从内存到寄存器 寄存器加1 写回内存
- m_mutex.lock();
- m_count++;
- m_mutex.unlock();
- }
- int count() const {
- return m_count;
- }
- private:
- int m_count;
- mutable std::mutex m_mutex; //临界区变量的定义
- //std::atomic<int> m_count;
- //原子操作变量类型 3个操作合并最小单元的原子操作
- // 原子操作的int类型
- };
- int work(int a){
- //do something
- return a + a;
- }
- template <typename Iter>
- void real_work(Counter& c, double& total_value, Iter b, Iter e){
- for(;b!=e;++b){
- total_value += work(*b);
- c.addCount();
- }
- }
- bool is_work_finished(Counter& c, int max_times){
- if(c.count() == max_times){
- std::cout << "work工作已经完成啦!\n" << std::endl;
- return true;
- }
- //std::cout << "work工作_没有完成呢" << std::endl;
- return false;
- }
- int main(){
- std::cout << "最大并发数=" << std::thread::hardware_concurrency() << std::endl;
- // Counter c1;
- // std::cout << c1.count()<< std::endl;
- // c1.addCount();
- // c1.addCount();
- // std::cout << c1.count()<< std::endl;
- std::vector<int> vec;
- for(int i=0;i<10000000;++i){
- vec.push_back(rand() % 100);
- }
- //没跑一次的时候来计数
- Counter c1;
- double total_value = 0.0f;
- for(auto v : vec){
- total_value += work(v);
- c1.addCount();
- }
- std::cout << "计数器的执行次数=" << c1.count() << "结果=" << total_value << std::endl;
- //开多线程来做同样的工作 三个线程都会去操作的对象:c2和total_value 共享变量
- Counter c2;
- total_value = 0.0f;
- auto iter1 = vec.begin() + (vec.size() / 3);
- auto iter2 = vec.begin() + (vec.size() / 3 * 2);
- //开一个子线程 后台服务 一定要使用共享变量c2
- //问题在这里:线程之间如何保证数据是一致的?
- std::thread service_back([&c2](){
- while (!is_work_finished(c2, 10000000))
- {
- /* 当返回true的时候 该线程才算执行完毕 否则死循环里 */
- }
-
- });
- //一共三个线程 主线程 子线程t1 子线程t2
- // lambda函数? 知识盲区
- // 引用传进去:c2 total_value
- // 作为值传进去:两个迭代器
- std::thread t1([&c2,&total_value,iter1,iter2](){
- real_work(c2,total_value,iter1,iter2);
- });
- auto end = vec.end();
- std::thread t2([&c2,&total_value,iter2,end](){
- real_work(c2,total_value,iter2,end);
- });
- //主线程里 做第一区间的
- real_work(c2,total_value,vec.begin(),iter1);
- t1.join();
- t2.join();
- std::cout << "multithread_计数器的执行次数=" << c2.count() << "结果=" << total_value << std::endl;
- service_back.join();
- return 0;
- }
复制代码
|
|