冯诺依曼机器的并发—带着脚镣跳舞

来源:互联网 发布:深圳软件定制开发公司 编辑:程序博客网 时间:2024/04/28 19:20

并发已经成了一个看起来永远聊不完的话题,可是有人真的想过并发的实质吗?当然如果不从哲学意义上讨论,仅仅从实用角度考虑的,现行的并发方案确实已经很不错了,然而事实却远远没有这么简单。
我 在前面很多文章中谈到了并发,并且说明了在冯氏机器上其实现的难度,到底为什么?我们知道操作系统的意义之一就是模拟了硬件,可是操作系统模拟硬件只是为 了提供一个比真实硬件相对通用的接口,我们把事情想得更加实质一点,操作系统是由编程语言编写的,其实也是一个软件,也就是一个二进制的执行流,多进程的 意义并没有什么大不了的,我们只需要考虑一个进程就可以了,多个进程只是通过硬件mmu分离地址空间然后通过OS管理的多个二进制执行流,这多个执行流之 间可以看作是没有交互的(我们不讨论进程间通信)。然而线程共享了地址空间,事情就变得复杂了,传统操作系统的传统进程提供的是对真实硬件的模拟但是现代 的线程操作系统的进程却不是对真实硬件的模拟,在现代操作系统中,进程只是一个资源的容器,而线程才是真正的执行流。
我们考虑最简单的情况,最开始的冯诺依曼机器,单cpu,那么显然是单执行流,人类往往很容易形成思维定势,以后的机器几乎都是这种单执行流的机器,甚至 强大的C语言本质上就是在模拟单cpu的机器,那么C++语言,以及基于C语言的linux,甚至windows,unix在本质上都是单cpu执行流的 模拟,也许有人会持有反对观点,这并不稀奇,因为这正是我马上就要解释的。我们看看现在的C语言多么花哨,用C语言写成了线程库,那么利用这个库的C语言 写的程序就支持了多线程,那么我们必须面对多线程这个本不应该在冯氏家族出生的怪胎。多线程起初只是为了合理的利用处理器资源,但是现在多线程就意味着并 发,多线程的程序在多cpu机器上有了并发的优势,在《关于两个世界体系的对话》一文中说道,一切几乎都是IO(读写内存其实是把内存作为外设的io), 以 C语言为代表的传统的IO,实际上是单CPU上单任务工作模式的投影,那么c语言写成的多线程程序实际上也是单cpu的工作模式,也是io为本的,时钟校 准机制不允许随意并发,本来它是不能并发的,如果非要并发,那么好办,戴上枷锁吧,从中可以看出,用c语言搭起来的舞台,舞者必须带着脚镣并发跳舞,进一 步,c语言是在冯氏机器的工作缩影,那么冯氏机器搭起来的舞台,舞者也必须带着脚镣跳舞,那么现在的多核cpu,甚至多cpu是怎么一回事呢?它们是否突 破了冯氏机器的脚镣的束缚呢?完全没有。看看它们的实现吧,随便了解一点比如MESI的知识就会发现多核cpu包括多cpu机制里面处处都是脚镣,同步 啊,各种锁啊都是,MESI就是一个例子,只不过其强大的性能和许多花哨的功能掩盖了沉重的脚镣。
冯氏机器往上就是c语言,说白了c语言就是冯氏机器的零件,赋值语句就是io指令,语句就是代码,变量就是数据…用c语言写的一个程序实际上就是一台冯氏 计算机,如果用c语言写了一个多线程的程序,那么就相当于这是一台多核或者多cpu的机器,这里我们假定机器上只跑一个进程,所谓多个进程只不过是多了一 层操作系统的管理而已。那么为何冯氏机器不能摆脱枷锁呢?从历史上考虑是因为当时没有考虑到并行,当时是以任务的存在为基准考虑计算机设计的,而不是从任 何的执行上考虑的,当时只是为了使得任务被完成而不考虑怎样完成或者叫完成的过程,因此,一个任务就是一次顺序的动作,就像我们人做事情一样,也是一个顺 序的过程,先做什么再做什么,统筹学早就已经成了一门学科,我们人类更关心任务能否完成,往往都是只在乎结果而不会享受过程,因此人类串行的大脑当然更容 易想象得出串行的机器,但是这只是原因之一,原因之二就是人类骨子里天生的权力意志。
作为人类,总希望能统治别人,平等是人类永远实现不了的梦想,有差距人类才可以进化,强者永远都会存在,因此这样的人类发明出来的代替人自身的东西当然不 能是以平等为基础的,因此诞生了cpu中心论,cpu就是一切的命令发出地,既然有了统治与被统治,有了主和次,那么并行就很难实现,真正并行的前提就是 大家彼此平等,可能你会说,为何两个平等的cpu不能去掉枷锁并行跑呢,当然不能,这里的不平等并不是说主事者的不平等,而是统治者和被统治者的不平等, 举个例子就是cpu和外设的不平等,cpu和内存的不平等,内存或者外设只能听候cpu的命令将数据从总线取下或者将数据放到总线上反过来它却不能直接命 令cpu(中断的方式?当然不是)。Cpu提供了多道程序设计而外设却没有,cpu可以运行管理流而外设却不可以…在这种模式之下,如果cpu要访问一个 资源,就要自己先给资源加上锁,这样可以阻止和自己平等的另一个统治者和自己竞争,然后等它用完了资源必须释放锁,这时另一个统治者才可以访问同一个资 源,如果资源和cpu平等的话,cpu就不用再加锁了,因为资源可以自己处理互斥,它自己可以仲裁谁可以访问谁必须等待,可能你还会说,资源自己仲裁的时 候不还是要锁吗?当然是的,但是这已经是更加底层的层次了,在执行这个层次上锁就消除了,如果用这种平等的观点对待cpu和io外设的话,操作系统就可以 把io指令也抽象给进程虚拟机了,因为此时io外设有了cpu的智能,io指令再也不是敏感指令了。人类的统治欲望加给计算机就成了以cpu为统治者的冯 氏机器。
我们看一下c语言编程,其实不管什么语言编程,大体上大同小异,编程的时候其实就好比cpu在执行指令,比如当我写i++的时候其实就是cpu将变量i递 增了,当我写printf的时候实际上就是cpu发出了写标准输出的命令,只不过一切都是静态的罢了。从这个意义上来说cpu完全在执行的时候替代了人的 角色,人统治着这个破败不堪的世界,cpu同样统治着那个只有0和1的世界,人类不会让位统治权,cpu让位统治权也是很难,因为人类发明了计算机就必须 找一个统治者来代理自己统治0,1世界,毕竟人对于平等没有任何经验,而且造物主往往会按照自己的样子来进行创造。再一个,我们编程实际上也是本着主谓宾 的原则进行的,既然是主谓宾,那么主和宾的地位本来就是不同的,我们可以实行君主立宪,让没有任何执行能力的总线来做主,这不失为一个好的办法,也就是总 线负责仲裁资源的访问,限制实体的行为,包括cpu的行为,但是这样的话我们的编程习惯将大大受影响,就好比《关于两个世界体系的对话》里面说到的IO Monad,大家都很不习惯,并发问题在冯氏机器上实际上就是一个执行顺序问题,而执行的顺序化是冯氏机器的特征之一,进一步执行本身是靠时钟驱动的,只 要时钟校准了,那么并发问题就解决了,我们换一种方式解决时钟校准问题就是用同一个时钟,但是用谁的呢?当然是用总线的了,因为大家都联在总线上,总线相 对于大家来说是平等的,最终的总线上还有一个仲裁器,当然仲裁器内部可能又会有锁(也可以没有),不过那已经不是机器架构的范畴了。无锁并不是不能存在 锁,而是说不能在执行代码的时候特意加锁,比如cpu不用把加锁当成同步的手段,而是直接访问,由被访问者自己仲裁,不过那时的机器可能就不是cpu在执 行指令了,可能真的就是大家一起来了。
      C语言是什么?c语言就是一个冯氏机器模拟者,不要想得太难,再重复一遍,它就是冯氏机器的零部件,它内部没有进程和线程的概念的。进程是操作系统的概 念,线程是抽象出来的概念,c语言本身并没有这些东西,之所以有了这么一些库,那纯粹是为了配合操作系统,比如你可以fork一个新进程,并且在某个场合 你必须fork出一个新进程,想深入学习冯氏机器,那学好标准的c语言就够了,当然如果你很了解冯氏机器,那么c语言相信你也学得很好。

原创粉丝点击