• C++11并发编程:原子操作atomic


    一:概述

      项目中经常用遇到多线程操作共享数据问题,常用的处理方式是对共享数据进行加锁,如果多线程操作共享变量也同样采用这种方式。

      为什么要对共享变量加锁或使用原子操作?如两个线程操作同一变量过程中,一个线程执行过程中可能被内核临时挂起,这就是线程切换,当内核再次切换到该线程时,之前的数据可能已被修改,不能保证原子操作。

      C++11提供了个原子的类和方法atomic,保证了多线程对变量原子性操作,相比加锁机制mutex.locak(),mutex.unlocak(),性能有几倍的提升。

      所需头文件<atomic>

    二:错误代码

     1 //全局变量
     2 int g_num = 0;
     3 
     4 void fun()
     5 {
     6     for (int i = 0; i < 10000000; i++)
     7     {
     8         g_num++;
     9     }
    10     return ;
    11 }
    12 
    13 int main()
    14 {
    15     //创建线程1
    16     thread t1(fun);
    17     //创建线程2
    18     thread t2(fun);
    19     t1.join();
    20     t2.join();
    21 
    22     cout << g_num << endl;
    23     getchar();
    24     return 1;
    25 }

    应该输出结果20000000,实际每次结果都不一样,总是小于该值,正是由于多线程操作同一变量而没有保证原子性导致的。

    三:加锁代码

     1 //全局变量
     2 int g_num = 0;
     3 mutex m_mutex;
     4 
     5 void fun()
     6 {
     7     for (int i = 0; i < 10000000; i++)
     8     {
     9         m_mutex.lock();
    10         g_num++;
    11         m_mutex.unlock();
    12     }
    13     return ;
    14 }
    15 
    16 int main()
    17 {
    18     //获取当前毫秒时间戳
    19     typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
    20     microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
    21     long long time1 = tp1.time_since_epoch().count();
    22 
    23     //创建线程
    24     thread t1(fun);
    25     thread t2(fun);
    26     t1.join();
    27     t2.join();
    28 
    29     cout << "总数:" << g_num << endl;
    30 
    31     //获取当前毫秒时间戳
    32     microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
    33     long long time2 = tp2.time_since_epoch().count();
    34     cout << "耗时:" << time2 - time1 << "ms" << endl;
    35 
    36     getchar();
    37     return 1;
    38 }

    执行结果:多次测试输出均为20000000,耗时在3.8s左右

    四:atomic原子操作代码

     1 //全局变量
     2 atomic<int> g_num = 0;
     3 
     4 void fun()
     5 {
     6     for (int i = 0; i < 10000000; i++)
     7     {
     8         g_num++;
     9     }
    10     return ;
    11 }
    12 
    13 int main()
    14 {
    15     //获取当前毫秒时间戳
    16     typedef chrono::time_point<chrono::system_clock, chrono::milliseconds> microClock_type;
    17     microClock_type tp1 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
    18     long long time1 = tp1.time_since_epoch().count();
    19 
    20     //创建线程
    21     thread t1(fun);
    22     thread t2(fun);
    23     t1.join();
    24     t2.join();
    25 
    26     cout << "总数:" << g_num << endl;
    27 
    28     //获取当前毫秒时间戳
    29     microClock_type tp2 = chrono::time_point_cast<chrono::milliseconds>(chrono::system_clock::now());
    30     long long time2 = tp2.time_since_epoch().count();
    31     cout << "耗时:" << time2 - time1 << "ms" << endl;
    32 
    33     getchar();
    34     return 1;
    35 }

    执行结果:多次测试输出均为20000000,耗时在1.3s左右

    五:总结

      c++11的原子类atomic相比使用加锁机制性能有2~3倍提升,对于共享变量能用原子类型的就不要再用加锁机制了。

    扫码关注公众号

    专注分享Java,C/C++,STL,Spring框架,mybatis框架,mysql,redis,分布式,高并发,设计模式,爬虫,docker,shell编程等相关技术,在这里一起探讨,一起学习,一起进步,不定期分享视频书籍资源,充分利用碎片化时间,让我们的技术之路更加有乐趣。

  • 相关阅读:
    [日常训练]大灾难
    [cf235D]Graph Game
    [日常训练]选课
    [日常训练]挂科
    [学习笔记]概率&期望
    [日常训练]yayamao的神题
    [学习笔记]原根
    LOJ#2132. 「NOI2015」荷马史诗
    LOJ#2131. 「NOI2015」寿司晚宴
    LOJ#2129. 「NOI2015」程序自动分析
  • 原文地址:https://www.cnblogs.com/woniu201/p/10119583.html
Copyright © 2020-2023  润新知