0 00:00:00,000 --> 00:00:07,040 1 00:00:07,080 --> 00:00:09,120 下面我们来讨论另一个 2 00:00:09,160 --> 00:00:12,480 经典的同步问题 3 00:00:12,520 --> 00:00:13,880 那这就是我们这里说的 4 00:00:13,920 --> 00:00:16,760 读者写者问题 5 00:00:16,800 --> 00:00:18,000 读者写者问题呢 6 00:00:18,040 --> 00:00:20,560 是我们在计算机系统当中 7 00:00:20,600 --> 00:00:23,760 经常碰到的一个经典问题 8 00:00:23,800 --> 00:00:26,800 它存在于数据库等很多 9 00:00:26,840 --> 00:00:29,640 共享资源的访问当中 10 00:00:29,680 --> 00:00:32,280 所谓的读者写者 11 00:00:32,320 --> 00:00:35,480 是指我们对共享数据的访问 12 00:00:35,520 --> 00:00:37,560 有两类使用者 13 00:00:37,600 --> 00:00:39,160 一类是读者 14 00:00:39,200 --> 00:00:42,080 他是只是读取数据不会去修改 15 00:00:42,120 --> 00:00:43,880 另一类是写者 16 00:00:43,920 --> 00:00:47,040 他可能会读和修改 17 00:00:47,080 --> 00:00:48,320 读的时候呢 18 00:00:48,360 --> 00:00:52,200 我是可以多过线程同时读 19 00:00:52,240 --> 00:00:54,600 写呢 那是我不可以同时写了 20 00:00:54,640 --> 00:00:55,800 因为一段数据 21 00:00:55,840 --> 00:00:57,600 你A和B同时往里写 22 00:00:57,640 --> 00:00:58,760 各写一部分 23 00:00:58,800 --> 00:01:01,480 最后写出来结果是谁也没法用的 24 00:01:01,520 --> 00:01:02,880 好 针对这种情况呢 25 00:01:02,920 --> 00:01:07,600 我们需要在各个线程之间进行同步 26 00:01:07,640 --> 00:01:09,160 那我们把这个问题抽象出来呢 27 00:01:09,200 --> 00:01:12,120 就是我们这里的读者写者问题 28 00:01:12,160 --> 00:01:14,480 那这里头我们到底 29 00:01:14,520 --> 00:01:16,600 有些什么样的原则呢 30 00:01:16,640 --> 00:01:19,280 首先第一个 读读允许 31 00:01:19,320 --> 00:01:21,120 也就说在同一时刻 32 00:01:21,160 --> 00:01:25,440 允许多个读者同时进行读操作 33 00:01:25,480 --> 00:01:28,600 第二条是说读写互斥 34 00:01:28,640 --> 00:01:30,840 如果有写者正在写 35 00:01:30,880 --> 00:01:33,560 那这时候你读者去读是没有意义的 36 00:01:33,600 --> 00:01:35,400 因为他可能正写个半截 37 00:01:35,440 --> 00:01:37,040 你读出来东西也不完整 38 00:01:37,080 --> 00:01:38,440 你没有意义 39 00:01:38,480 --> 00:01:40,800 另一种情况呢是 40 00:01:40,840 --> 00:01:42,920 没有读者的时候你才能写 41 00:01:42,960 --> 00:01:44,520 因为如果有读者在读 42 00:01:44,560 --> 00:01:45,440 你这时候就写 43 00:01:45,480 --> 00:01:48,040 那么你写了一半的过程当中 44 00:01:48,080 --> 00:01:49,640 读者读到数据一部分是旧的 45 00:01:49,680 --> 00:01:50,720 一部分是新的 46 00:01:50,760 --> 00:01:51,960 那这时候这个数据呢 47 00:01:52,000 --> 00:01:53,960 拿到一起来也是没法用的 48 00:01:54,000 --> 00:01:56,880 第三个呢 是写写互斥 49 00:01:56,920 --> 00:01:58,280 也就说两个写者 50 00:01:58,320 --> 00:02:00,080 同时往里写数据 51 00:02:00,120 --> 00:02:01,400 这也是不允许的 52 00:02:01,440 --> 00:02:02,640 因为A写一部分 53 00:02:02,680 --> 00:02:03,560 B写一部分 54 00:02:03,600 --> 00:02:06,640 写出来的结果呢它是不可用的 55 00:02:06,680 --> 00:02:09,080 这是我们读者写者问题 56 00:02:09,120 --> 00:02:12,120 所要遵守的三条规则 57 00:02:12,160 --> 00:02:13,480 依据这三条规则 58 00:02:13,520 --> 00:02:15,840 我们来看如何用信号量 59 00:02:15,880 --> 00:02:19,840 实现读者写者问题解决方案 60 00:02:19,880 --> 00:02:20,880 在这里头呢 61 00:02:20,920 --> 00:02:22,320 我们把刚才这些约束 62 00:02:22,360 --> 00:02:25,200 描述成信号量 63 00:02:25,240 --> 00:02:28,720 首先第一个呢 是读写互斥 64 00:02:28,760 --> 00:02:31,000 当然 读写互斥也负责 65 00:02:31,040 --> 00:02:32,840 写者与写者之间的互斥 66 00:02:32,880 --> 00:02:33,800 某种程度上来讲 67 00:02:33,840 --> 00:02:37,280 你可以认为它就是一个临界区 68 00:02:37,320 --> 00:02:39,960 但是临界区和这儿有点不一样 69 00:02:40,000 --> 00:02:40,800 这一块访问的时候 70 00:02:40,840 --> 00:02:43,280 多个读者是可以一起来访问的 71 00:02:43,320 --> 00:02:46,640 作为互斥的话它的初值是1 72 00:02:46,680 --> 00:02:48,800 然后还会再有一个计数 73 00:02:48,840 --> 00:02:51,560 这个计数呢 Rcount 74 00:02:51,600 --> 00:02:52,920 它是用来记录 75 00:02:52,960 --> 00:02:56,880 正在进行读操作的读者的数目 76 00:02:56,920 --> 00:02:59,960 它的初值呢是0 77 00:03:00,000 --> 00:03:03,960 还有一个就是信号量 CountMutex 78 00:03:04,000 --> 00:03:08,280 这个信号量是用来保护读者计数的 79 00:03:08,320 --> 00:03:11,040 也就说如果我一个读者开始读 80 00:03:11,080 --> 00:03:13,040 那么这时候呢它要把这个计数加1 81 00:03:13,080 --> 00:03:15,160 如果说多个读者前后脚进来 82 00:03:15,200 --> 00:03:17,240 那么它们同时对这个 83 00:03:17,280 --> 00:03:18,600 计数进行加1的话 84 00:03:18,640 --> 00:03:21,200 就有可能这个计数会出问题 85 00:03:21,240 --> 00:03:23,400 它们俩之间也需要协调 86 00:03:23,440 --> 00:03:25,520 好 这时候的访问呢应该是互斥的 87 00:03:25,560 --> 00:03:30,960 所以我们就有CountMutex这个信号量 88 00:03:31,000 --> 00:03:32,720 它是用来保护 89 00:03:32,760 --> 00:03:35,120 读写计数的互斥修改 90 00:03:35,160 --> 00:03:36,480 这时候呢任何时刻 91 00:03:36,520 --> 00:03:37,960 只允许一个线程 92 00:03:38,000 --> 00:03:39,640 可以来修改这个计数 93 00:03:39,680 --> 00:03:42,280 所以这个初值呢也是1 94 00:03:42,320 --> 00:03:46,120 有了这三个变量之后 95 00:03:46,160 --> 00:03:48,040 我们来看 我们实现的 96 00:03:48,080 --> 00:03:52,400 读者写者的解决方案是什么样的 97 00:03:52,440 --> 00:03:54,440 在这儿呢我们给出了 98 00:03:54,480 --> 00:03:56,400 读者进程 写者进程 99 00:03:56,440 --> 00:03:59,120 两边要做的核心操作一个是读 100 00:03:59,160 --> 00:04:00,760 一个是写 101 00:04:00,800 --> 00:04:01,880 那我们要进行 102 00:04:01,920 --> 00:04:04,640 互斥保护这事做起来比较简单 103 00:04:04,680 --> 00:04:07,920 两边都加上互斥信号量的 104 00:04:07,960 --> 00:04:10,160 P操作和V操作 105 00:04:10,200 --> 00:04:11,520 这是写者 106 00:04:11,560 --> 00:04:12,280 它可以理解为 107 00:04:12,320 --> 00:04:16,200 完全是一个临界区问题 108 00:04:16,240 --> 00:04:17,560 在读者这头呢 109 00:04:17,600 --> 00:04:20,040 我们如果说跟写者相对应 110 00:04:20,080 --> 00:04:22,680 它也是一个临界区 111 00:04:22,720 --> 00:04:25,040 前面一个P操作后面一个V操作 112 00:04:25,080 --> 00:04:26,640 但是它有一些不同 113 00:04:26,680 --> 00:04:28,960 就在于我如果第一个读者 114 00:04:29,000 --> 00:04:32,480 进来的时候申请P操作 115 00:04:32,520 --> 00:04:34,120 跟写者进行互斥 116 00:04:34,160 --> 00:04:35,160 第二个来的时候 117 00:04:35,200 --> 00:04:36,640 它就不能那么申请了 118 00:04:36,680 --> 00:04:38,440 所以这个申请操作呢 119 00:04:38,480 --> 00:04:40,400 只是对于第一个读者 120 00:04:40,440 --> 00:04:43,080 所以我会在前面呢加一个判断 121 00:04:43,120 --> 00:04:46,400 如果说当前的读者计数是0 122 00:04:46,440 --> 00:04:47,720 第一个读者进来的时候 123 00:04:47,760 --> 00:04:49,840 他需要申请 124 00:04:49,880 --> 00:04:52,280 然后第二的话他就不用了 125 00:04:52,320 --> 00:04:53,720 第二个就相当于 126 00:04:53,760 --> 00:04:55,360 他只需要计数加1 127 00:04:55,400 --> 00:04:56,920 也就说第一个进来的时候 128 00:04:56,960 --> 00:04:59,200 不但申请并且计数加1 129 00:04:59,240 --> 00:05:00,760 初始值计数是0 130 00:05:00,800 --> 00:05:01,880 那他就变成一个 131 00:05:01,920 --> 00:05:04,120 好 第二个来说只加1 132 00:05:04,160 --> 00:05:06,800 等他出来的时候呢也是一样的 133 00:05:06,840 --> 00:05:08,840 计数减一这是每个都要减的 134 00:05:08,880 --> 00:05:12,080 但只是对最后一个离开的读者 135 00:05:12,120 --> 00:05:14,680 他才需要释放这个 136 00:05:14,720 --> 00:05:16,440 读写互斥的这个信号量 137 00:05:16,480 --> 00:05:19,040 好 这样的话以便于后边的 138 00:05:19,080 --> 00:05:22,040 写者可以开始写操作 139 00:05:22,080 --> 00:05:25,080 那这时候说我们刚才读者计数 140 00:05:25,120 --> 00:05:27,880 这个数的修改呢也需要保护 141 00:05:27,920 --> 00:05:29,560 那这时候我再在前面 142 00:05:29,600 --> 00:05:35,400 加上一个计数的信号量 CountMutex 143 00:05:35,440 --> 00:05:38,280 底下这个地方呢也是一样的 144 00:05:38,320 --> 00:05:40,080 有了这些操作之后 145 00:05:40,120 --> 00:05:41,720 我们再来对照说 146 00:05:41,760 --> 00:05:42,800 这是不是能满足 147 00:05:42,840 --> 00:05:45,880 我们前面说的三条原则 148 00:05:45,920 --> 00:05:47,760 仔细核对每一种情况 149 00:05:47,800 --> 00:05:49,080 这时候是满足的 150 00:05:49,120 --> 00:05:52,640 我们在满足前面三条的基础上 151 00:05:52,680 --> 00:05:54,520 我们看我们这个实现办法 152 00:05:54,560 --> 00:05:56,360 还有些什么样的特征 153 00:05:56,400 --> 00:05:58,200 大家看一下如果说 154 00:05:58,240 --> 00:06:00,680 我一直在里头有读者在读 155 00:06:00,720 --> 00:06:04,320 后面的读者是一直能进去的 对吗 156 00:06:04,360 --> 00:06:05,560 如果这个时候 157 00:06:05,600 --> 00:06:11,680 有一个写者申请写 会是什么情况 158 00:06:11,720 --> 00:06:13,680 那它就等着呢 159 00:06:13,720 --> 00:06:15,760 一直等到什么时候呢 160 00:06:15,800 --> 00:06:18,040 等到所有的读者全部离开 161 00:06:18,080 --> 00:06:21,120 如果说有一个读者在里头读 162 00:06:21,160 --> 00:06:23,520 这时候下一个读者又进来了 163 00:06:23,560 --> 00:06:26,280 好 那这时候他先于那个写者的 164 00:06:26,320 --> 00:06:27,640 头一个读者离开 165 00:06:27,680 --> 00:06:30,920 也就说后来的读者一定是会先于 166 00:06:30,960 --> 00:06:34,840 等待的写者进行读操作的 167 00:06:34,880 --> 00:06:36,320 那对于这种情况呢 168 00:06:36,360 --> 00:06:40,480 就是我们这里说的读者优先 169 00:06:40,520 --> 00:06:41,480 读者优先呢 170 00:06:41,520 --> 00:06:43,680 在某些情况下是有意义的 171 00:06:43,720 --> 00:06:45,280 比如说我们在这里头 172 00:06:45,320 --> 00:06:47,080 我读数据更是 173 00:06:47,120 --> 00:06:48,920 我优先级高这是可以的 174 00:06:48,960 --> 00:06:50,920 但是对于通常的数据更新来讲 175 00:06:50,960 --> 00:06:52,480 我们希望读到的数据 176 00:06:52,520 --> 00:06:53,840 都是最新的数据 177 00:06:53,880 --> 00:06:57,160 所以这时候呢我们希望是写者优先 178 00:06:57,200 --> 00:06:59,040 这就是我们这里说到的 179 00:06:59,080 --> 00:07:01,600 读者写者问题的两种优先策略 180 00:07:01,640 --> 00:07:04,040 一个是读者优先 181 00:07:04,080 --> 00:07:05,640 只要有读者正在读 182 00:07:05,680 --> 00:07:08,360 后续的读者就可以直接进入 183 00:07:08,400 --> 00:07:09,520 在这种情况下呢 184 00:07:09,560 --> 00:07:12,680 只要读者是持续不断地进入 185 00:07:12,720 --> 00:07:14,720 写者就处于饥饿 186 00:07:14,760 --> 00:07:17,920 而另一种策略呢是写者优先 187 00:07:17,960 --> 00:07:21,360 只要是有写者就绪 188 00:07:21,400 --> 00:07:25,120 那么写者就应尽快执行写操作 189 00:07:25,160 --> 00:07:26,360 这句话的意思是 190 00:07:26,400 --> 00:07:29,520 后来的读者就必须阻塞 191 00:07:29,560 --> 00:07:33,000 如果说有写者持续不断地写入 192 00:07:33,040 --> 00:07:36,800 那么这时候呢读者会处于饥饿状态 193 00:07:36,840 --> 00:07:39,360 这是两种不同的优先策略 194 00:07:39,400 --> 00:07:40,840 那这时候问 195 00:07:40,880 --> 00:07:43,240 这种如何来实现 196 00:07:43,280 --> 00:07:45,240 还有没有其它的优先策略 197 00:07:45,280 --> 00:07:46,200 那实际上还有 198 00:07:46,240 --> 00:07:48,800 就是我两边公平的 199 00:07:48,840 --> 00:07:50,760 有读者就绪了 200 00:07:50,800 --> 00:07:53,440 那么写者不能往里写 201 00:07:53,480 --> 00:07:55,880 有写者就绪了读者不能往里写 202 00:07:55,920 --> 00:07:58,360 这时候两边工程也是可以的 203 00:07:58,400 --> 00:08:01,360 那这些做法呢如何来实现 204 00:08:01,400 --> 00:08:05,080 就请同学们下去思考了 205 00:08:05,120 --> 00:08:08,760 这是我们用信号量来实现的 206 00:08:08,800 --> 00:08:10,560 读者写者问题 207 00:08:10,600 --> 00:08:13,080 那接下来呢我们用管程 208 00:08:13,120 --> 00:08:16,080 来尝试一下解决读者写者问题 209 00:08:16,120 --> 00:08:17,480 我们说管程是把 210 00:08:17,520 --> 00:08:19,440 你的这些同步操作 211 00:08:19,480 --> 00:08:20,840 封装到一个类里头 212 00:08:20,880 --> 00:08:22,240 这就是我们管程 213 00:08:22,280 --> 00:08:24,240 对于读者写者问题呢 214 00:08:24,280 --> 00:08:26,640 我们对外提供的基本方法有两个 215 00:08:26,680 --> 00:08:28,160 一个是读 216 00:08:28,200 --> 00:08:30,440 如果说在前面已经有写者 217 00:08:30,480 --> 00:08:33,400 我一直等到写者结束我开始读 218 00:08:33,440 --> 00:08:34,480 出来的时候呢 219 00:08:34,520 --> 00:08:37,720 我看是不是有其他的写者 220 00:08:37,760 --> 00:08:40,080 而另一个呢是写操作 221 00:08:40,120 --> 00:08:42,120 看前面有没有读者或者写者 222 00:08:42,160 --> 00:08:43,640 如果没有 他开始写 223 00:08:43,680 --> 00:08:45,760 写完之后看有没有另外的读者 224 00:08:45,800 --> 00:08:48,480 或者写者 把他们唤醒 225 00:08:48,520 --> 00:08:49,920 让他继续进行操作 226 00:08:49,960 --> 00:08:51,240 这时候我在管程里 227 00:08:51,280 --> 00:08:53,080 我维护一些什么内容 228 00:08:53,120 --> 00:08:56,120 我维护这样四个变量 229 00:08:56,160 --> 00:08:57,800 当前正在读的读者 230 00:08:57,840 --> 00:08:59,200 当前正在写的写者 231 00:08:59,240 --> 00:09:00,520 等待读的读者 232 00:09:00,560 --> 00:09:02,520 和等待写的写者 233 00:09:02,560 --> 00:09:04,520 这四个它有一些关系 234 00:09:04,560 --> 00:09:06,720 你比如说正在读和正在写 235 00:09:06,760 --> 00:09:10,320 这两个只会有一个是大于0的 236 00:09:10,360 --> 00:09:11,680 好 那等的呢 237 00:09:11,720 --> 00:09:13,760 可能都会大于0都有可能的 238 00:09:13,800 --> 00:09:15,000 好 然后我们在这儿呢 239 00:09:15,040 --> 00:09:16,640 管程里头设置一个锁 240 00:09:16,680 --> 00:09:19,440 然后我们设置两个条件变量 241 00:09:19,480 --> 00:09:21,920 一个是可以去读 242 00:09:21,960 --> 00:09:23,880 一个是可以去写 243 00:09:23,920 --> 00:09:28,000 我们看详细的方法如何来做 244 00:09:28,040 --> 00:09:29,280 那我们刚才说 245 00:09:29,320 --> 00:09:32,080 对外提供一个开始读一个完成读 246 00:09:32,120 --> 00:09:34,120 这是对于读者这一头的 247 00:09:34,160 --> 00:09:36,040 它内部的实现呢 248 00:09:36,080 --> 00:09:38,720 对于管程我们都会申请 249 00:09:38,760 --> 00:09:40,480 管程的互斥访问 250 00:09:40,520 --> 00:09:43,160 这是一开头 一结尾 251 00:09:43,200 --> 00:09:45,880 在内部呢 它开始读的时候呢 252 00:09:45,920 --> 00:09:48,800 一定是当前正在读的计数要加1 253 00:09:48,840 --> 00:09:52,520 那在什么时候会进行等待呢 254 00:09:52,560 --> 00:09:53,960 判断条件然后把它 255 00:09:54,000 --> 00:09:56,160 排到等的队列里头 256 00:09:56,200 --> 00:09:57,920 等的计数加1 257 00:09:57,960 --> 00:10:02,480 并且排到这个条件变量上 258 00:10:02,520 --> 00:10:03,800 等它出来的时候呢 259 00:10:03,840 --> 00:10:07,080 等待读的计数减1 260 00:10:07,120 --> 00:10:08,400 那关键的问题是 261 00:10:08,440 --> 00:10:10,320 在这里我加什么样的条件 262 00:10:10,360 --> 00:10:12,120 这个条件呢又体现出来 263 00:10:12,160 --> 00:10:14,320 我们到底是对读者优先 264 00:10:14,360 --> 00:10:17,400 对写者优先 还是两边公平 265 00:10:17,440 --> 00:10:19,680 我们在这儿呢设的条件是 266 00:10:19,720 --> 00:10:23,160 如果说正在有写者在写 267 00:10:23,200 --> 00:10:27,720 或者说有写者在申请写 268 00:10:27,760 --> 00:10:28,600 那这时候呢 269 00:10:28,640 --> 00:10:30,200 我就进入等待队列 270 00:10:30,240 --> 00:10:31,920 也就说写者是优先的 271 00:10:31,960 --> 00:10:35,680 只要有写者它都优先于这个读者 272 00:10:35,720 --> 00:10:38,160 好 然后它完成读的时候怎么做呢 273 00:10:38,200 --> 00:10:42,080 申请互斥访问管程 这是一样的 274 00:10:42,120 --> 00:10:44,080 然后计数减1 275 00:10:44,120 --> 00:10:46,240 然后关键的问题是说 276 00:10:46,280 --> 00:10:48,440 我需要唤醒哪一些 277 00:10:48,480 --> 00:10:50,080 那么这个唤醒的条件不同呢 278 00:10:50,120 --> 00:10:52,200 也体现你优先策略不同 279 00:10:52,240 --> 00:10:55,240 我们在这儿设的呢没有读者 280 00:10:55,280 --> 00:10:56,960 那这时候最后一个读者 281 00:10:57,000 --> 00:10:59,280 是不是有写者等着 282 00:10:59,320 --> 00:11:00,640 如果有写者等着 283 00:11:00,680 --> 00:11:03,680 那我就让他释放了 284 00:11:03,720 --> 00:11:06,880 另一头呢是写者这头 285 00:11:06,920 --> 00:11:08,760 我们也是开始写 完成写 286 00:11:08,800 --> 00:11:11,320 这两个需要你实现一个操作 287 00:11:11,360 --> 00:11:12,840 那具体来说呢 288 00:11:12,880 --> 00:11:16,520 申请和释放管程的互斥访问 289 00:11:16,560 --> 00:11:17,920 这个都是一样的 290 00:11:17,960 --> 00:11:19,280 开始写的时候 291 00:11:19,320 --> 00:11:21,880 当前正在写的计数加1 292 00:11:21,920 --> 00:11:23,800 那他最多会是1 293 00:11:23,840 --> 00:11:26,400 好 在这儿之前他会进行等待 294 00:11:26,440 --> 00:11:27,760 等待的时候呢 295 00:11:27,800 --> 00:11:29,600 等待写者计数加1 296 00:11:29,640 --> 00:11:33,440 并且加入到等待队列当中 297 00:11:33,480 --> 00:11:35,120 这是这里的条件变量 298 00:11:35,160 --> 00:11:37,400 好 关键问题也是一样的 299 00:11:37,440 --> 00:11:39,000 那地方的条件 300 00:11:39,040 --> 00:11:40,960 我们在这儿设条件呢是 301 00:11:41,000 --> 00:11:43,160 有正在写的写者 302 00:11:43,200 --> 00:11:45,520 或者说有正在读的读者 303 00:11:45,560 --> 00:11:47,320 我就会等着 304 00:11:47,360 --> 00:11:51,440 也就说如果有等待申请读的读者 305 00:11:51,480 --> 00:11:52,800 我是不等着的 306 00:11:52,840 --> 00:11:53,840 好 这种情况呢 307 00:11:53,880 --> 00:11:58,080 就说明它是写者优先的 308 00:11:58,120 --> 00:12:01,760 而对于释放的这一头也是一样 309 00:12:01,800 --> 00:12:02,840 计数减1 310 00:12:02,880 --> 00:12:05,400 当前正在写的写者计数减1 311 00:12:05,440 --> 00:12:07,080 然后唤醒哪些 312 00:12:07,120 --> 00:12:08,840 这地方我们设条件是 313 00:12:08,880 --> 00:12:12,920 先优唤醒等待写的 314 00:12:12,960 --> 00:12:15,240 如果说你释放的时候 315 00:12:15,280 --> 00:12:16,920 另外有一个等待写的 316 00:12:16,960 --> 00:12:18,480 我优先唤醒它 317 00:12:18,520 --> 00:12:20,960 如果说没有等待写的 else 318 00:12:21,000 --> 00:12:23,280 我才去唤醒读者 319 00:12:23,320 --> 00:12:25,520 等待读的这些读者把它唤醒 320 00:12:25,560 --> 00:12:27,440 所以从这几个角度来讲呢 321 00:12:27,480 --> 00:12:32,040 我们在这个管程里是写者优先的 322 00:12:32,080 --> 00:12:33,560 好 我们从这儿可以看到 323 00:12:33,600 --> 00:12:35,320 基于管程的实现 324 00:12:35,360 --> 00:12:39,000 我们更方便的能够把这种 325 00:12:39,040 --> 00:12:40,720 优先策略呢体现出来 326 00:12:40,760 --> 00:12:42,320 这种优先策略体现 327 00:12:42,360 --> 00:12:43,880 也是比较直接的 328 00:12:43,920 --> 00:12:45,520 所以从这个角度来说呢 329 00:12:45,560 --> 00:12:47,520 管程是简化了 330 00:12:47,560 --> 00:12:52,880 处理同步问题的实现方法 331 00:12:52,920 --> 00:12:55,680 好 今天的课呢就上到这里 下课 332 00:12:55,720 --> 00:12:55,920 333 00:12:55,960 --> 00:12:56,000