同步的本质
首先我们得明白操作系统是如何执行程序的。对于进程和线程,操作系统设计者的目的是从概念上简化编程模型,使编程显得更自然,更符合思维习惯。
操作系统设计者为使用进程和线程来编程提供了一个假设条件,即进程和线程各自的执行流是连贯的,没有任何断续执行的现象。但是实际上(以单CPU系统为例),从系统实现的底层看起来,这些进程和线程的执行流是支离破碎的,并且这些破碎的执行流片断被CPU以某种方式(即操作系统的调度程序)组合成一个串行的、混合在一起的执行流,以此推动操作系统不断运行。
问题就在这里,同步问题的根源就在于看起来连贯的执行流实际上是破碎的。破碎的执行流会造成什么问题呢?
比如有两个执行流A和B,A对现在需要对一个数据进行操作,但是这个操作被分割成了相连的两块执行流碎片,而另外一个执行流B本来需要在A完成这个数据操作之后才能取到这个数据然后进行它自己的计算,可是由于A对数据本应完整的操作被分割成了相连的两部分,然后CPU在A的碎片之间插入了B的取数这样一个执行流片断。
这样一来,程序的行为就不符合我们原本所设想的那样,程序运行的结果就会出错。同步的本质就是让CPU不要把A的数据操作分割开,不让B有机会错误的横插一杠进来扰乱A,以保证正确的执行顺序,这样才能得到正确的我们想要的结果。
不管你看起来执行得多么快的操作,都有可能被操作系统打断,从而形成碎片,导致无法预料的结果。
所以,应该在需要精确时序的地方使用同步,而不是根据这个操作快不快来判断。所谓需要精确时序场合,其实就是数据的使用或操作的执行存在依赖性的地方,对于代码来说,就是完成某项操作时对参与的进程或线程执行顺序存在依赖性的代码块。