【高并发】为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题?看完这篇我懂了!
写在前面
大冰:小菜童鞋,前几天讲的知识点复习了吗?
小菜:复习了,大冰哥,我回去关注了你的公众号,收藏和转发了你的文章,看了好几遍呢!!
大冰:好的,一定要好好复习啊,今天,我们来分析一个诡异的问题:为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题呢? 今天的内容很重要,它能够帮助你更加深刻的理解线程的原子性问题,一定要好好听!
诡异的问题
我们在32位多核CPU的计算机上以多线程的方式读写long类型的共享变量时,线程已经将变量成功写入了内存,但是重新读取出来的数据和之前写入的数据不一致,这到底是为什么呢?
原因分析
其实,造成这个问题的根本原因就是线程的原子性问题,而线程的原子性问题最终的“幕后黑手”是线程切换,如果能够禁用线程切换就能够解决这个问题了!在操作系统层面来看,操作系统做线程切换需要依赖CPU的中断机制,所以说,禁止CPU发生中断就能够禁止线程切换。
这种方案在单核CPU上是可行的,但是并不适合多核CPU。
其实,就分析为何在32位多核CPU上执行long型变量的写操作会出现诡异的Bug问题,我们需要从数据类型占用的存储空间来分析。long型变量是64位的,在32位CPU上执行写操作会被拆分成两次写操作(分别是写高32位和写低32位)。我们可以用下图来表示。
32位单核CPU
在32位单核CPU场景下,同一时刻只有一个线程执行,禁止CPU中断,也就是说,在单核CPU上,操作系统不会重新调度线程,实际上,也就是禁止了线程切换。如果一个线程获取到CPU资源,就可以一直执行下去,直到线程结束为止。在这个线程中,对于long型变量的两次写操作,要么都被执行,要么都没有被执行,两次写操作具有原子性,不会出现写入的数据和读取的数据不一致的情况。
我们可以简单的使用下图来表示32位单核CPU写long型数据这个过程。
由上图我们可以看出,在32位单核CPU中,禁止了线程切换之后,所有的线程都是串行执行的,对于long型变量的两次写操作,要么都被执行,要么都没有被执行,两次写操作具有原子性,不会出现写入的数据和读取的数据不一致的情况。
32位多核CPU
在32位多核CPU场景下,同一时刻,可能有两个甚至更多的线程在同时执行。假设有两个线程分别是线程A和线程B,线程A执行在CPU-01上,线程B执行在CPU-02上,此时,禁用CPU中断,只能保证在每个CPU上执行的线程是连续的,并不能保证同一时刻只有一个线程执行,如果线程A和线程B同时写long型变量的高32位的话,那么,就有可能出现诡异的Bug问题,也就是说,明明已经将变量成功写入内存了,但是重新读取出来的数据却不是自己写入的!!
我们可以简单的使用下图来表示32位多核CPU并发写long型数据这个过程。
由上图我们可以看出,在32位多核CPU中,如果有多个线程同时对long类型的数据进行写操作,即使中断CPU操作,也只能保证在每个CPU上执行的线程是连续的,并不能保证同一时刻只有一个线程执行。如果多个线程同时写long型变量的高32位的话,那么,就有可能出现诡异的Bug问题。
总结
long型变量是64位的,在32位CPU上执行写操作,会被拆分成写高32位和写低32位两部分,如果此时有多个线程同时写long型变量的高32位的话,就有可能出现诡异的Bug问题。
注意:不只是long型变量,在32位多核CPU上并发写64位数据类型的数据,都会出现类似的诡异问题!!!
如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习高并发编程技术。
写在最后
大冰:这就是今天的主要内容了,今天的内容非常重要,它能够帮助你更加深刻的理解并发编程的原子性问题,小菜童鞋,回去后一定要好好复习下。
小菜:好的,大冰哥,回去我一定好好复习。
最后,附上并发编程需要掌握的核心技能知识图,祝大家在学习并发编程时,少走弯路。
- 点赞 1
- 收藏
- 分享
- 文章举报
- 关于JQuery中的ajax请求或者post请求的回调方法中的操作执行或者变量修改没反映的问题
- 关于JQuery中的ajax请求或者post请求的回调方法中的操作执行或者变量修改没反映的问题
- 通过View.post()获取View的宽高引发的两个问题:1post的Runnable何时被执行,2为何View需要layout两次;以及发现Android的一个小bug
- 构造函数的职责 -- 关于全局变量的构造函数里执行太多复杂操作导致的问题
- 关于操作php文件载入顺序时会出现的bug以及载入顺序问题
- 通过View.post()获取View的宽高引发的两个问题:1post的Runnable何时被执行,2为何View需要layout两次;以及发现Android的一个小bug
- SQLite并发操作下的分析与处理,解决database is locked,以及多线程下执行事务等问题
- 在Activity中开启一个线程执行网络操作出现的问题
- 如果类a继承类b,实现接口c,而类b和接口c中定义了同名变量,请问会出现什么问题?(瞬联)
- 项目中遇到的[数据库并发]操作问题
- C语言中以十六进制输出字符型变量会出现'ffffff"的问题
- 多核CPU服务器无法安装SQL Server 2005问题
- 树莓派 Learning 002 装机后的必要操作 --- 05 给树莓派搭建“x86 + pi”环境 -- 安装**32位运行库** -- 解决`E:未发现软件包 xxx` 问题
- Android面试题 你经常写复杂的界面,那Android刷新Ui有什么特点?在这个过程中做哪些操作会出现问题
- [承前]Saxon执行XQuery时的"重复变量(duplicate global variable)"声明问题
- 记一次诡异的问题:跟多进程多次执行application的onCreate有关
- 多线程环境下对变量的读写操作的原子性问题【baidu】
- C语言变量声明问题——变量定义一定要放在所有执行语句/语句块的最前面吗?
- 【实战Java高并发程序设计】5:让普通变量也享受原子操作
- sql server中高并发情况下 同时执行select和update语句死锁问题 (一)