Lamport面包店算法
Lamport面包店算法是解决多个线程并发访问一个共享的单用户资源的互斥问题的算法。 由莱斯利·兰波特发明[1]。 算法类比Lamport把这个并发控制算法非常直观地类比为顾客去面包店采购。面包店一次只能接待一位顾客的采购。已知有N位顾客要进入面包店采购,按照次序安排他们在前台登记一个签到号码。该签到号码逐次增加1。顾客根据签到号码的由小到大的顺序依次入店购货。完成购买的顾客在前台把其签到号码归0。 如果完成购买的顾客要再次进店购买,就必须重新排队。 这个类比中的顾客就相当于线程,而入店购货就是进入临界区独占访问该共享资源。由于计算机实现的特点,存在两个线程获得相同的签到号码的情况,这是因为两个线程几乎同时申请排队的签到号码,读取已经发出去的签到号码情况,这两个线程读到的数据是完全一样的,然后各自在读到的数据上找到最大值,再加1作为自己的排队签到号码。为此,该算法规定如果两个线程的排队签到号码相等,则线程id号较小的具有优先权。 进入临界区已经拿到排队签到号码的线程,要轮询检查自己是否可以进入临界区。即检查n个线程中,自己是否具有最小的非0排队签到号码;或者自己是具有最小的非0排队签到号码的线程中,id号最小的。 可以用伪代码表示上述检查: (a, b) < (c, d) 等价于: (a < c) or ((a == c) and (b < d)) 非临界区一旦线程在临界区执行完毕,需要把自己的排队签到号码置为0,表示处于非临界区. 算法实现定义
伪代码 // declaration and initial values of global variables
Entering: array [1..NUM_THREADS] of bool = {};
Number: array [1..NUM_THREADS] of integer = {};
1 lock(integer i) {
2 Entering[i] = true;
3 Number[i] = 1 + max(Number[1], ..., Number[NUM_THREADS]);
4 Entering[i] = false;
5 for (j = 1; j <= NUM_THREADS; j++) {
6 // Wait until thread j receives its number:
7 while (Entering[j]) { /* nothing */ }
8 // Wait until all threads with smaller numbers or with the same
9 // number, but with higher priority, finish their work:
10 while ((Number[j] != 0) && ((Number[j], j) < (Number[i], i))) { /* nothing */ }
11 }
12 }
13
14 unlock(integer i) {
15 Number[i] = 0;
16 }
17
18 Thread(integer i) {
19 while (true) {
20 lock(i);
21 // The critical section goes here...
22 unlock(i);
23 // non-critical section...
24 }
25 }
讨论每个线程只写它自己的Entering[i]、Number[i],只读取其它线程的这两个数据项。 这个算法不需要基于硬件的原子(atomic)操作实现,即它可以纯软件实现。 使用Entering数组是必须的。假设不使用Entering数组,那么就可能会出现这种情况:设进程i的优先级高于进程j(即 具体实现时,可以把上述伪代码中的忙等待(busy wait),换成交出线程的执行权,例如 参见外部链接
参考文献
|
Portal di Ensiklopedia Dunia