原子性和可见性

来源:互联网 发布:mac eclipse 编辑:程序博客网 时间:2024/04/30 03:50

一、定义

1、可见性

在多核处理器中,如果多个线程对一个变量进行操作,但是这多个线程可能被分配到多个处理器中运行,那么编译器会对代码进行优化,当线程要处理该变量时,多个处理器会将变量从主存中复制一份分别存储到自己的片上存储器,等到进行完操作后,在赋值回主存。(这样做的好处是提高了陨星 的速度,因为在处理过程中多个处理器减少了同主存通信的次数);同样在单核处理器中这样由于“备份造成的问题同样存在”。
这样的优化带来的问题之一是变量可见性——如果线程ti与线程t2分别被安排在了不同的处理器上面,那么t1与t2对于变量A的修改时相互不可见,如果t1给A赋值,然后t2又赋新值,那么t2的操作就将t1的操作覆盖掉,这样会产生不可预料的后果。所以,即使有些操作是原子性的,但是如果不具有可见性,那么多个处理器中备份的存在就会使原子性失去意义。

2、原子性

原子性是拒绝多线程操作的,简而言之——不被线程调度中断的操作。如:
赋值或者return 比如”a = 1”和 “return a”;这样的操作都具有原子性

3、非原子性操作

类似”a += b”这样的操作不具有原子性,其可能要进行如下三个步骤:
(1)取出a和b
(2)计算a+b
(3)讲计算结果写入内存

如果有两个线程t1,t2在进行这样的操作。t1在做完第二步之后还没来得及把数据写入内存就中断了,于是t2开始执行,t2执行完t1就完成它的第三步,那么t2的计算就被无视了。

类似的,像a++这样的操作也都不具有原子性。

4、原子性和可见性的关系

两者并没有直接的关系
(1)多线程中可见性造成的问题:
多个线程对相同变量的修改相互不可见,导致某部分操作被覆盖,比如:
count++;t1与t2两个线程准备操作它,当t1在自己的存储空间修改完count之后,并没有及时将count刷到主内存,而是执行了count的其他操作——这时候,t2开始执行该操作,但是它并没有发现count值进行了改变,这样就会导致count值没有及时更新而产生未可知的错误。

(2)其他问题:
同样是count++;t1与t2执行该语句,t1只比t2稍慢一点,t2修改后count,t1又将自己的结果写入count,这样t1的结果会对t2的结果进行覆盖,这种覆盖会造成意想不到的错误。

(3)讨论:
可见性的问题造成了多线程的问题一部分,确定变量的可见性只能解决一部分多线程的问题,而操作原子性是解决多线程问题的总的方法,因为它拒绝多个线程在同一时刻操作相同的一段内存。

0 0
原创粉丝点击