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();