C++多线程不加锁操作同一个整数
#include <iostream> #include <thread> #include <vector> #include <chrono> #include <atomic> using namespace std; int num = 0; //volatile int num = 0; //atomic<int> num = 0; void add() { int times = 0; for (int i = 0; i < 10000; ++i) { //std::cout << std::this_thread::get_id() << ":" << num++ << std::endl; num++; this_thread::sleep_for(chrono::milliseconds(0)); times++; } std::cout << "thread id: [" << std::this_thread::get_id() << "] run times:" << times << std::endl; } int main() { vector<thread> vects; for (int i = 0; i < 2; ++i) { vects.push_back(thread(add)); } for (auto& t : vects) { t.join(); } std::cout << "main thread, final num: " << num << std::endl; }
上面是两线程同时对num执行自加操作, 实际输出结果:
thread id: [29524] run times:10000
thread id: [30444] run times:10000
main thread, final num: 17766
两个进程每个线程执行对同一个数连加10000次, 加锁或使用atomic的值应该是20000.
网上有说单个数值可以不用加锁的原因是, 单条cpu指令取这个整数值是不会出错的. 他们推荐类对象或struct要加锁, 比如struct strTest{int a, int b}, 取strTest数据, 需要两条指令才能完成, 先取a值, 再取b值, 多线程时会有其它指令在中间正好修改了b值.
volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。