C++ 多线程的错误和如何避免(9)

有时候使用 std::atomic 比使用 mutexes 更高效

问题分析:使用多线程更新一些简单数据时,比如 int 型,bool 型等等,可以使用 std::atomic,这比 mutex 来得更为高效。

比如,我们一般这样用:

int counter;
....
mu.lock();
counter++;
mu.unlock();

现在,我们可以这样用,

std::atomic<int> counter;
...
counter++;

概念

原子操作:可以把原子操作理解为一种不需要用到互斥量加锁(无锁)技术的多线程编程方式

互斥量:多线程编程中保护共享数据

使用场合

原子操作:针对的一般都是一个变量,而不是一个代码段

互斥量:加锁一般针对一个代码段(几行代码)

 

std::atomic 是个类模板,用来封装某个类型的值,如下

#include <thread>
#include <atomic>
#include <iostream>

std::atomic<int> g_mycount;

void mythread()
{
    for (int i = 0; i < 10000000; i++)
    {
        g_mycount++;
    }
    return;
}

int main()
{
    std::thread myobj1(mythread);
    std::thread myobj2(mythread);
    myobj1.join();
    myobj2.join();
    std::cout << "两个线程执行完毕,最终的g_mycount的结果是: " << g_mycount << std::endl;
}

最后会打印出:两个线程执行完毕,最终的g_mycount的结果是: 20000000

如果不使用 std::atomic,即直接定义

int g_mycount = 0;

最后会打印出:两个线程执行完毕,最终的g_mycount的结果是: 10240079

注意:该结果是个随机值,因为两个线程读写值不受限制

另外,原子变量不可以这样定义,如下

auto atm_copy = atm; 

我们需要使用 .load(),以原子方式读取 atomic 对象的值

auto atm_copy = atm.load();

  

posted @ 2022-05-22 15:20  strive-sun  阅读(82)  评论(0编辑  收藏  举报