zoukankan      html  css  js  c++  java
  • 【C++多线程】std::atomic<T>

    面向的问题

      对简单临界资源的访问,如果使用mutex开销较大。

      如有两个线程,对一个变量进行操作,一个线程读这个变量的值,一个线程往这个变量中写值。即使是一个简单变量的读取和写入操作,如果不加锁,也有可能会导致读写值混乱(一条语句可能会被拆成3、4条汇编语句来执行,所以仍然有可能混乱)

     1 #include <iostream>
     2 #include <thread>
     3 using namespace std;
     4 int g_count = 0;
     5  
     6 void mythread1() {
     7     for (int i = 0; i < 1000000; i++) {
     8         g_count++;
     9     }
    10 }
    11  
    12 int main() {
    13     std::thread t1(mythread1);
    14     std::thread t2(mythread1);
    15     t1.join();
    16     t2.join();
    17     cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
    18 }

       使用std::mutex来解决上述对临界资源访问的问题。结果正常,但是每一次循环都要加锁解锁是的程序开销很大。

     1 #include <iostream>
     2 #include <thread>
     3 #include <mutex>
     4 using namespace std;
     5 int g_count = 0;
     6 std::mutex mymutex;
     7 
     8 void mythread1() {
     9     for (int i = 0; i < 1000000; i++) {
    10         std::unique_lock<std::mutex> u1(mymutex);
    11         g_count++;
    12     }
    13 }
    14  
    15  
    16 int main() {
    17     std::thread t1(mythread1);
    18     std::thread t2(mythread1);
    19     t1.join();
    20     t2.join();
    21     cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
    22 }

    std::atomic<T>

      std::atomic<T>包含在头文件<atomic>中。可以把原子操作理解成一种:不需要用到互斥量加锁(无锁)技术的多线程并发编程方式。原子操作:在多线程中不会被打断的程序执行片段。从效率上来说,原子操作要比互斥量的方式效率要高。互斥量的加锁一般是针对一个代码段,而原子操作针对的一般都是一个变量。原子操作,一般都是指“不可分割的操作”;也就是说这种操作状态要么是完成的,要么是没完成的,不可能出现半完成状态。std::atomic来代表原子操作,是个类模板。其实std::atomic是用来封装某个类型的值。

     1 #include <iostream>
     2 #include <thread>
     3 #include <atomic>
     4 using namespace std;
     5 std::atomic<int> g_count = 0; //封装了一个类型为int的 对象(值)
     6 
     7 void mythread1() {
     8     for (int i = 0; i < 1000000; i++) {
     9         g_count++;
    10     }
    11 }
    12  
    13 int main() {
    14     std::thread t1(mythread1);
    15     std::thread t2(mythread1);
    16     t1.join();
    17     t2.join();
    18     cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
    19 }

     一般atomic原子操作,针对++,–,+=,-=,&=,|=,^=是支持的,其他操作不一定支持。如下使用g_count = g_count + 1就会产生错误。

     1 #include <iostream>
     2 #include <thread>
     3 #include <atomic>
     4 using namespace std;
     5 std::atomic<int> g_count = 0; //封装了一个类型为int的 对象(值)
     6  
     7 void mythread1() {
     8     for (int i = 0; i < 1000000; i++) {
     9          //虽然g_count使用了原子操作模板,但是这种写法既读又写,
    10          //会导致计数错误
    11              g_count = g_count + 1;
    12     }
    13 }
    14 
    15 int main() {
    16     std::thread t1(mythread1);
    17     std::thread t2(mythread1);
    18     t1.join();
    19     t2.join();
    20     cout << "正常情况下结果应该是200 0000次,实际是" << g_count << endl;
    21 }

      其他需要注意的地方

    1 std::atomic<int> atm = 0;
    2  
    3 cout << atm << endl;

      这里只有读取atm是原子操作,但是整个这一行代码 cout << atm << endl; 并不是原子操作,导致最终显示在屏幕上的值是一个“曾经值”。

    1 std::atomic<int> atm = 0;
    2  
    3 auto atm2 = atm; //不可以

      这种拷贝初始化不可以,会报错。

    atomic<int> atm2(atm.load());

      load():以原子方式读atomic对象的值。

    atm2.store(12);

      store():以原子方式写。

    参考

    https://blog.csdn.net/qq_38231713/article/details/106093115

  • 相关阅读:
    javaScript 匿名函数 理解
    javaScript this理解
    javaScript原型链理解
    Django学习笔记
    python mysql应用
    华为OBS上传,与modelart添加标签--python
    pyhton 定时任务
    制作滑动验证码(未完待续)
    测试扫描支付功能
    js 易错点(未完待续)
  • 原文地址:https://www.cnblogs.com/chen-cs/p/13254219.html
Copyright © 2011-2022 走看看