0 00:00:00,000 --> 00:00:07,480 1 00:00:07,520 --> 00:00:10,720 下面我们来讨论线程的实现 2 00:00:10,760 --> 00:00:12,320 那在这里头呢 3 00:00:12,360 --> 00:00:15,520 线程的实现方式呢有这样几种 4 00:00:15,560 --> 00:00:16,920 在最早的时候 5 00:00:16,960 --> 00:00:18,640 实际上在我们的操作系统里呢 6 00:00:18,680 --> 00:00:20,600 并没有多线程的支持 7 00:00:20,640 --> 00:00:22,800 那用户提出了这种需求 8 00:00:22,840 --> 00:00:25,080 那我们首先可以做的方式呢 9 00:00:25,120 --> 00:00:28,000 是用户自己来写函数库 10 00:00:28,040 --> 00:00:30,880 在用户态来实现一个进程 11 00:00:30,920 --> 00:00:33,120 内部的并发性的提高 12 00:00:33,160 --> 00:00:36,160 那这就是我们这里说到的用户线程 13 00:00:36,200 --> 00:00:39,000 在用户空间里通过函数库的形式 14 00:00:39,040 --> 00:00:43,760 来支持线程的创建删除和切换 15 00:00:43,800 --> 00:00:46,240 那 这是我们在几种提供 16 00:00:46,280 --> 00:00:49,720 用户库的方式提供的线程实现 17 00:00:49,760 --> 00:00:52,400 那在用户线程支持 18 00:00:52,440 --> 00:00:53,800 有了一定基础之后 19 00:00:53,840 --> 00:00:55,240 那这个功能呢 20 00:00:55,280 --> 00:00:56,960 也会做到操作系统内核里头 21 00:00:57,000 --> 00:00:58,120 这种做法呢类似于 22 00:00:58,160 --> 00:01:01,040 我们在网络里头做法 23 00:01:01,080 --> 00:01:02,400 网络最开始也不是 24 00:01:02,440 --> 00:01:03,520 写在操作系统里头的 25 00:01:03,560 --> 00:01:05,480 那只是用了一段时间之后呢 26 00:01:05,520 --> 00:01:08,280 它才变成操作系统内部的一个模块 27 00:01:08,320 --> 00:01:10,160 好 那在操作系统内核 28 00:01:10,200 --> 00:01:12,240 实现线程支持呢 29 00:01:12,280 --> 00:01:15,520 它会更自然效果会更好 30 00:01:15,560 --> 00:01:18,000 那我们现在的操作系统呢 31 00:01:18,040 --> 00:01:22,440 基本上都支持内核态的线程 32 00:01:22,480 --> 00:01:24,920 好 在这两种基础之上呢 33 00:01:24,960 --> 00:01:26,680 在SOLARIS里头呢又进行了一种 34 00:01:26,720 --> 00:01:29,080 新的尝试 叫轻权进程 35 00:01:29,120 --> 00:01:31,520 那也就是说在用户态实现的线程 36 00:01:31,560 --> 00:01:33,080 和内核态实现的线程 37 00:01:33,120 --> 00:01:34,800 它俩各有各自的优缺点 38 00:01:34,840 --> 00:01:36,400 那在SOLARIS里头呢 39 00:01:36,440 --> 00:01:38,440 希望把这两种结合起来 40 00:01:38,480 --> 00:01:40,800 就出现了这种轻权进程 41 00:01:40,840 --> 00:01:42,360 那下面我们具体来看 42 00:01:42,400 --> 00:01:45,640 这三种做法它都是怎么来做 43 00:01:45,680 --> 00:01:48,520 用户线程是指说我们在通过一个 44 00:01:48,560 --> 00:01:51,160 用户库来完成线程的管理 45 00:01:51,200 --> 00:01:52,440 这包括线程的 46 00:01:52,480 --> 00:01:56,520 创建 中止 同步和调度 47 00:01:56,560 --> 00:01:59,760 那在这个图里呢我们描述了 48 00:01:59,800 --> 00:02:01,280 系统里的线程库里 49 00:02:01,320 --> 00:02:03,720 实现的基本方法 50 00:02:03,760 --> 00:02:05,520 在操作系统内核里头呢 51 00:02:05,560 --> 00:02:09,280 仍然只有进程控制块来描述 52 00:02:09,320 --> 00:02:11,280 处理机的调度的情况 53 00:02:11,320 --> 00:02:13,160 然后在这里头呢 54 00:02:13,200 --> 00:02:15,200 操作系统并不感知 55 00:02:15,240 --> 00:02:17,600 应用态有多线程的支持 56 00:02:17,640 --> 00:02:19,680 而多线程的支持呢 57 00:02:19,720 --> 00:02:24,840 是用户的函数库支持的多线程 58 00:02:24,880 --> 00:02:26,560 在应用程序内部 59 00:02:26,600 --> 00:02:29,240 通过构造相应的线程控制块 60 00:02:29,280 --> 00:02:31,200 来空置一个进程内部 61 00:02:31,240 --> 00:02:34,880 多个线程的交替执行和同步 62 00:02:34,920 --> 00:02:37,920 好 那用这种方式呢 63 00:02:37,960 --> 00:02:41,120 我们可以很好的支持多线程 64 00:02:41,160 --> 00:02:42,720 那它也有自己的好处 65 00:02:42,760 --> 00:02:44,800 比如说这里它有一些什么样的特征 66 00:02:44,840 --> 00:02:46,480 不依赖操作系统内核 67 00:02:46,520 --> 00:02:48,080 不依赖操作系统内核呢 68 00:02:48,120 --> 00:02:49,480 也就相当于内核 69 00:02:49,520 --> 00:02:51,720 不感知用户线程的存在 70 00:02:51,760 --> 00:02:52,960 那这也是最早 71 00:02:53,000 --> 00:02:54,560 为啥会做这件事情的缘故 72 00:02:54,600 --> 00:02:57,080 就是用于不支持线程的 73 00:02:57,120 --> 00:02:59,000 多进程操作系统 74 00:02:59,040 --> 00:03:00,880 好 那有了这个之后呢 75 00:03:00,920 --> 00:03:02,880 那用户你就会多一些事情 76 00:03:02,920 --> 00:03:04,280 在用户态实现线程 77 00:03:04,320 --> 00:03:05,880 这时候用户要自己来 78 00:03:05,920 --> 00:03:07,200 维护线程控制块 79 00:03:07,240 --> 00:03:10,600 要自己有一个相应的线程库 80 00:03:10,640 --> 00:03:11,840 那 有了这一条之后 81 00:03:11,880 --> 00:03:13,480 它还会带来好处就是 82 00:03:13,520 --> 00:03:15,400 用户态里的线程之间的 83 00:03:15,440 --> 00:03:17,200 切换它速度非常快 84 00:03:17,240 --> 00:03:19,560 没有用户到内核的切换 85 00:03:19,600 --> 00:03:22,000 然后用户也可以自己 86 00:03:22,040 --> 00:03:24,000 来写自己的调度算法 87 00:03:24,040 --> 00:03:25,200 因为我对应用 88 00:03:25,240 --> 00:03:27,600 我应用的开发者更了解 89 00:03:27,640 --> 00:03:29,600 这个多线程如何切换 90 00:03:29,640 --> 00:03:32,440 如何调度 它的性能会更好 91 00:03:32,480 --> 00:03:34,680 当然这种做法也有它的问题 92 00:03:34,720 --> 00:03:35,720 它的问题是什么 93 00:03:35,760 --> 00:03:39,160 由于线程发起系统调用而堵塞 94 00:03:39,200 --> 00:03:40,080 那这时候呢 95 00:03:40,120 --> 00:03:42,720 整个进程就进入等待状态了 96 00:03:42,760 --> 00:03:44,040 因为对于内核来讲 97 00:03:44,080 --> 00:03:45,840 并不知道你上面是多线程 98 00:03:45,880 --> 00:03:46,880 一个线程堵塞的时候 99 00:03:46,920 --> 00:03:49,400 把另一个线程继续运行下去 100 00:03:49,440 --> 00:03:50,560 要做到这一点的话 101 00:03:50,600 --> 00:03:52,400 必须有内核的支持 102 00:03:52,440 --> 00:03:54,040 好 然后不支持 103 00:03:54,080 --> 00:03:56,800 基于线程的处理机抢占 104 00:03:56,840 --> 00:03:57,880 这里指的是什么意思呢 105 00:03:57,920 --> 00:03:58,840 这里指的是说 106 00:03:58,880 --> 00:04:00,520 我们多进程系统里头 107 00:04:00,560 --> 00:04:01,640 通过抢占的方式 108 00:04:01,680 --> 00:04:02,880 让一个进程停下来 109 00:04:02,920 --> 00:04:05,400 然后让另一个进程继续运行 110 00:04:05,440 --> 00:04:08,320 那如果说我们是基于线程 111 00:04:08,360 --> 00:04:09,720 来做这件事情 112 00:04:09,760 --> 00:04:11,440 那这样的话我操作系统 113 00:04:11,480 --> 00:04:13,760 就没有办法让一个线程停下来 114 00:04:13,800 --> 00:04:16,160 然后这一个进程内部的 115 00:04:16,200 --> 00:04:17,800 另一个线程来运行 116 00:04:17,840 --> 00:04:19,640 那这种的必须由 117 00:04:19,680 --> 00:04:21,680 当前的线程主动放弃 118 00:04:21,720 --> 00:04:23,840 我才可以做这种切换 119 00:04:23,880 --> 00:04:25,800 好 那再有一个 120 00:04:25,840 --> 00:04:27,640 就是分配CPU的时间 121 00:04:27,680 --> 00:04:29,160 对于操作系统来说 122 00:04:29,200 --> 00:04:30,400 这个分配是由 123 00:04:30,440 --> 00:04:31,840 操作系统内核来控制的 124 00:04:31,880 --> 00:04:32,720 所以它是以 125 00:04:32,760 --> 00:04:35,040 进程为单位来进行分配 126 00:04:35,080 --> 00:04:38,000 如果你里头有多个线程 127 00:04:38,040 --> 00:04:38,960 那这多个线程 128 00:04:39,000 --> 00:04:40,640 每个线程分配到的时间呢 129 00:04:40,680 --> 00:04:42,360 相对来说就会变少 130 00:04:42,400 --> 00:04:42,520 131 00:04:42,560 --> 00:04:43,760 132 00:04:43,800 --> 00:04:43,800