File tree 2 files changed +2
-2
lines changed
2 files changed +2
-2
lines changed Original file line number Diff line number Diff line change 99
99
100
100
管程有一个很重要的特性,即任一时刻只能有一个活跃线程调用管程中过程,这一特性使线程在调用执行管程中过程时能保证互斥,这样线程就可以放心地访问共享变量。管程是编程语言的组成部分,编译器知道其特殊性,因此可以采用与其他过程调用不同的方法来处理对管程的调用,比如编译器可以在管程中的每个过程的入口/出口处加上互斥锁的加锁/释放锁的操作。因为是由编译器而非程序员来生成互斥锁相关的代码,所以出错的可能性要小。
101
101
102
- 管程虽然借助编译器提供了一种实现互斥的简便途径,但这还不够,还需要一种线程间的沟通机制。首先是等待机制:由于线程在调用管程中某个过程时,发现某个条件不满足,那就在无法继续运行而被阻塞。这里需要注意的是:在阻塞之前,操作系统需要把进入管程的过程入口出的互斥锁给释放掉 ,这样才能让其他线程有机会调用管程的过程。
102
+ 管程虽然借助编译器提供了一种实现互斥的简便途径,但这还不够,还需要一种线程间的沟通机制。首先是等待机制:由于线程在调用管程中某个过程时,发现某个条件不满足,那就在无法继续运行而被阻塞。这里需要注意的是:在阻塞之前,操作系统需要把进入管程的过程入口处的互斥锁给释放掉 ,这样才能让其他线程有机会调用管程的过程。
103
103
104
104
其次是唤醒机制:另外一个线程可以在调用管程的过程中,把某个条件设置为真,并且还需要有一种机制及时唤醒等待条件为真的阻塞线程。这里需要注意的是:唤醒线程(本身执行位置在管程的过程中)如果把阻塞线程(其执行位置还在管程的过程中)唤醒了,那么需要避免两个活跃的线程都在管程中导致互斥被破坏的情况。为了避免管程中同时有两个活跃线程,我们需要一定的规则来约定线程发出唤醒操作的行为。目前有三种典型的规则方案:
105
105
Original file line number Diff line number Diff line change @@ -88,7 +88,7 @@ A是共享变量。粗略地看,可以估计执行流程为:第一个线程t
88
88
...
89
89
}
90
90
91
- A是共享变量。粗略地看,可以估计执行流程为:线程thr1先被创建,等了10ms后,线程thr2再被创建。一般情况下,这就导致了thr1先于thr2执行,即第5行会先于第10行执行 ,得到预期的结果。但可能出现一种执行情况:线程thr1在执行第5句前,由于某种原因进入了休眠,导致线程thr2执行第10行在前,线程th1执行第5行在后,导致获得非预期的错误结果。
91
+ A是共享变量。粗略地看,可以估计执行流程为:线程thr1先被创建,等了10ms后,线程thr2再被创建。一般情况下,这就导致了thr1先于thr2执行,即第5行会先于第9行执行 ,得到预期的结果。但可能出现一种执行情况:线程thr1在执行第5句前,由于某种原因进入了休眠,导致线程thr2执行第10行在前,线程th1执行第5行在后,导致获得非预期的错误结果。
92
92
93
93
这里出现问题的根源是线程在对共享变量进行访问时,违反了临界区的预期顺序原则。解决这样的问题需要给线程的相关代码位置加上同步操作(如通过信号量或条件变量等),确保线程间的执行顺序符合预期,修改后的代码如下:
94
94
You can’t perform that action at this time.
0 commit comments