悉野小楼

导航

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 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。

posted on 2023-08-11 14:41  悉野  阅读(64)  评论(0编辑  收藏  举报