第 25 章 关于并发的对话
教授: 现在我们要开始讲操作系统三大主题中的第二个:并发。
学生: 我以为有四大主题……
教授: 不,那是在这本书的旧版本中。
学生: 呃,好的。那么什么是并发,教授?
教授: 想象我们有一个桃子——
学生: (打断)又是桃子!您和桃子有什么关系?
教授: 读过 T.S.艾略特的作品吗?《The Love Song of J. Alfred Prufrock》中写到 “Do I dare to eat a peach”,还有那些有趣的东西……
学生: 哦,是的!是在高中的英语课上学到的。我非常喜欢那个部分。
教授: (打断)这与此无关,我只是喜欢桃子。不管怎样,想象一下桌子上有很多桃子,还有很多人想吃它们。比方说,我们这样做:每个食客首先在视觉上识别桃子,然后试图抓住并吃掉桃子。这种方法有什么问题?
学生: 嗯……好像你可能会看到别人也看到的桃子。如果他们先拿到,当你伸出手时,就拿不到桃子了!
教授: 确实!那么我们应该怎么做呢?
学生: 好吧,可能会想一个更好的方法来解决这个问题。也许会排队,当你到达前面时,抓起桃子并继续前进。
教授: 好!但是你的方法有什么问题?
学生: 哎,我必须做所有的工作吗?
教授: 是点。
学生: 好的,让我想想。好吧,我们曾经让很多人同时抓起桃子,速度更快。但以我的方式,我们只是一次一个,这是正确的,但速度较慢。最好的方法是既快速又正确。
教授: 你真的开始让我刮目相看了。事实上,你刚才告诉了我们关于并发的所有知识!做得好。
学生: 我做到了?我以为我们只是在谈论桃子。还记得,这通常是您再次开讲计算机的一部分。
教授: 的确如此。我道歉!永远不要忘记具体概念。好吧,事实证明,存在某些类型的程序,我们称之为多线程(multi-threaded)应用程序。每个线程(thread)都像在这个程序中运行的独立代理程序,代表程序做事。但是这些线程访问内存,对于它们来说,每个内存节点就像一个桃子。如果我们不协调线程之间的内存访问,程序将无法按预期工作。懂了吗?
学生: 有点懂了。但是为什么我们要在操作系统课上谈论这个问题?这不就是应用程序编程吗?
教授: 好问题!实际上有几个原因。首先,操作系统必须利用锁(lock)和条件变量(condition variable)这样的原语,来支持多线程应用程序,我们很快会讨论。其次,操作系统本身是第一个并发程序——它必须非常小心地访问自己的内存,否则会发生许多奇怪而可怕的事情。真的,会变得非常可怕。
学生: 我明白了。听起来不错。我猜,还有更多的细节,是不是?
教授: 确实有……
导师的下一步建议:
并发是操作系统的第二大支柱,也是程序员最容易出错的地方。多个线程共享同一内存地址空间,如果没有协调机制,竞态条件就会导致
第 26 章将从最基础的并发问题讲起:线程是什么?竞态条件如何产生?为什么简单的 counter++ 在多线程下会出错?