[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yCvaP7LN-1596187339986)(https://imgkr2.cn-bj.ufileos.com/db1944cc-0cc4-4ee0-befd-c3cd2059a58d.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=oo617Eq22IS84ftmiXEcXP2k4Bs%253D&Expires=1596272169)]
- 「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」。
- 当然 不论新老朋友 我相信您都可以 从中获益。如果觉得 「不错」 的朋友,欢迎 「关注 + 留言 + 分享」,文末有完整的获取链接,您的支持是我前进的最大的动力!
写在前面
该文章的大部分内容都是翻译自是黑莓 10
实时操作系统 QNX Neutrino
的开发手册,该手册不仅详细地阐述了 BlackBerry 10 OS 的原理以及 OS 的体系结构,还描述了其 QNX Neutrino 微内核的详细信息 (包括进程线程、多和处理、网络架构、文件系统等…非常完整…)。
我阅读了其中「描述进程和线程」的精华部分,觉得写的非常不错,特意翻译 (主要靠有道和 Google 翻译) 跟大家分享一下 (部分内容有改动)。
手册中详细描述了许多关于 Linux 函数调用涉及底层方面的细节,在本文中我大都没有贴出来,感兴趣的朋友强烈建议去拜读一下原文!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a4qNB0NR-1596187339991)(https://imgkr2.cn-bj.ufileos.com/336441d3-e4fc-450e-9271-1b4ef3a4f6ed.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=9VR8cSORG5jWR8cqJTrBoc4TXIo%253D&Expires=1596271687)]
- 原文地址:https://developer.blackberry.com/native/documentation/dev/rtos/arch/about_system_architecture.html
Part 1. 进程和线程基础
在我们开始讨论线程、进程、时间片和所有其他的精彩的概念之前,让我们先来建立一个类比。
我要做的首先是 说明线程和进程是如何工作的。我能想到的最好的方法 (不涉及实时系统的设计) 是在某种情况下想象我们的线程和进程。
进程就像一栋房子
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aqsJviv8-1596187339993)(https://imgkr2.cn-bj.ufileos.com/e283ed13-3541-4a3d-8ec9-6b845d6434f4.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=kecaKX3GOyWpSaR9vTCJZBokCR4%253D&Expires=1596244026)]
房子实际上是 具有某些属性的容器 (例如卧室数量、占地面积、区域划分等)。
如果您以这个角度来看,房子实际上并不会主动做任何事情————它是一个 被动的对象。这实际上就是进程干的事情了 (充当容器)。
线程就像是居住者
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G691OjEY-1596187339995)(https://imgkr2.cn-bj.ufileos.com/3d262b67-f931-41fa-8328-bcce20034a5b.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=F7QcbvtpKj0DWD1dvrh8Jx7sqhw%253D&Expires=1596244392)]
居住在房子里面的人是 活动的对象,他们可以使用各种房间,看电视、做饭、洗澡等等等…
单线程
如果您独居过,那么您就会知道————您可以在家里的任何时间做您任何想做的事,因为家里面没有其他人,您只要遵从内心的规则就好。
多线程
如果在您的房子中再另外添加一个人,情况将发生巨变。
假设您结婚了,那么现在您的家里住着您和您的配偶。因此您不能在 任何时间 都能够使用厕所,因为您需要首先确保您的配合不在其中!
如果您有两个 负责任的成年人 居住在房屋中,那么通常您可以在 「安全性」 这一块儿稍微放松一些 (因为您知道另一个成年人会尊重您的空间,不会试图故意在厨房放火之类的…)。
但是,如果把几个 熊孩子 混在一起,事情就会变得更加有趣了…
说回进程和线程
就像是房屋占用土地一样,进程也要占用内存。
也正如房屋拥有者可以随意进入他们想去的任何房间一样,进程中的线程也 都拥有 对该内存区域访问的权限。
如果某个线程被分配了某些东西 (例如哥哥进程出去买了游戏机🎮回家),那么其他所有线程都可以立即访问它 (因为它存在于公共地址空间中————都在房子里)。
同样,如果给进程分配额外多的一块空间,则新的区域也能够用于所有线程。
这里的窍门在于识别内存是否应该对进程中的所有线程可用。
-
如果是,那么您将需要让所有线程同步它们对其的访问。
-
如果不是,那么我们将假定它只能用于某个特定的线程 (在这种情况下,因为只有特定线程能够访问它,我们可以在假设线程不会自己把自己玩儿坏的前提下,不需要同步操作)。
从日常的生活中我们知道,事情并不是那么简单。
现在我们已经了解了基本特征 (所有内容都是共享的),下面我们来深入探究一下事情变得有趣的地方以及原因。
下图显示了我们表示线程和进程的方式。进程是一个圆圈,代表“容器”概念(地址空间),三个长方形是线程。在本文中,您将看到类似这样的图。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZzEFSWdf-1596187339997)(https://imgkr2.cn-bj.ufileos.com/2c253102-4bd3-4164-892f-315c5fba4467.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=WnCM4PjMf048bO3dnw%252FgnGCI8jo%253D&Expires=1596244922)]
互斥
在生活中,如果您想洗个澡,并且已经有人在洗手间了,您将不得不等待。线程又是如何处理的呢?
这是通过一种叫做 互斥 (mutual exclusion) 的操作完成的。和你想的差不多——当涉及到 特定资源 时,许多线程是互斥的。
当你想要独占浴室洗澡时,你通常会走进浴室,从里面锁上门。任何想要上厕所的人都会被锁挡住。当你洗完之后,你会打开门,允许其他人进入。
这就是线程的作用。一个线程使用一个叫做 互斥锁 (mutex) 的对象 (互斥锁 MUTual EXclusion 的首字母缩写)。这个对象就像门上的锁 —— 一旦一个线程锁定了互斥锁,其他线程就不能获得该互斥锁,直到拥有它的线程释放它。就像门锁一样,等待获得互斥锁的线程将被阻挡。
互斥锁和门锁的另一个有趣的相似之处是,互斥锁实际上是一种 “建议” 锁 (“advisory” lock)。如果一个线程不遵守使用互斥锁的约定,那么保护就没有用了。在我们的房子比喻中,这就像有人不顾门和锁的惯例,从一堵墙闯进盥洗室。
优先级
如果卫生间现在上锁了,有很多人在等着使用怎么办?显然,所有人都坐在外面,等着洗手间里的人出来。
真正的问题是:当门打开时会发生什么?谁下一个去?
你会想,让等待时间最长的人下一个走或许是 “公平的”。又或者,让年龄最大的人排在第二位也可能是 “公平的”。有很多方法可以确定什么是“公平”。
我们通过两个因素来解决这个问题:优先级 和 等待的时长。
假设两个人同时出现在锁着的浴室门口。其中一个有一个有急事 (例如:他们开会已经迟到了…),而另一个没有。让那个有急事的人去做下一个