lamport面包店算法详细讲解及代码实现

本文详细介绍了Lamport算法,也称为面包店算法,用于解决分布式系统中的资源互斥访问问题。通过类比顾客在面包店购买的过程,阐述了算法的原理和步骤,包括时间戳的更新规则。此外,给出了算法的伪代码实现,并讨论了其适用场景,如P2P结构的系统和Hadoop的HDFS。
摘要由CSDN通过智能技术生成

1 算法详解

1978年Lamport发表的文章《Time, Clocks, and the Ordering of Events in a Distributed System》

算法检查了分布式系统中一个事件先于另一个时间发生的概念,并且定义了时间的偏序,给出了一种用于同步逻辑时钟系统的分布式算法。该系统可用于对事件进行完全排序。使用解决同步问题的方法说明了总排序的使用。该算法专门用于同步物理时钟,并推导出时钟可能不同步的程度。

有兴趣的读者可以深入阅读这篇论文!
链接:https://dl.acm.org/doi/pdf/10.1145/359545.359563

1.1 一个较为直观的解释

lamport算法又称为面包店算法,它解决了多个线程并发访问一个共享的单用户资源的互斥问题的算法。
Lamport把这个并发控制算法直观的类比为顾客去面包店采购。这个步骤如下所示:
step1: 有n个顾客进入面包房买巧克力面条蒸蛋糕,安排他们按照次序在前台登记签到的号码。该签到号码依次加1.
step2: 根据签到号码的由小到大的顺序依次进店买好吃的蛋糕。
step3: 完成购物的顾客在前台把自己的签到号码归0。如果完成购买的顾客要再次进店需要重新排队
特别说明: 同时进入面包店采购的两个或两个以上的顾客有可能得到相同的号码,多个顾客如果拿到相同的号码,则规定按照顾客名字的字典顺序进行排序。
抽象对应:
顾客--------------------->进程
入店购货--------------->进入临界区独占访问共享资源
相同号码---------------->由于计算机实现的特点,存在两个线程获得相同的签到号码的情况,这是因为两个线程几乎同时申请排队的签到号码,两个线程读到的号码是完全一样的,所以,在该算法中规定如果两个线程的排队签到号码相等,则线程id号较小的具有优先权。

1.2 Lamport算法的时间戳原理

  • 每个事件对应一个Lamport时间戳,初始值为0;
  • 如果事件在节点内发生,时间戳+1;
  • 如果事件属于发送事件,时间戳+1并在消息中带上该时间戳;
  • 如果事件属于接收事件,时间戳=Max(本地时间戳,消息中的时间戳)+1。

1.3 Lamport算法的5个原则

  • 为了请求资源,进程A发送消息(Tm:A)给所有的其他进程,并且把这个消息放到进程队列中,Tm是消息的时间戳;
  • 当进程B接收到了进程A的(Tm:A)请求后,会把它放到自己的请求队列,然后发送一个带有时间戳的确认消息给A;
  • 为了释放资源,进程A移除所有(Tm:A)的请求消息,然后发送带时间戳的A释放资源请求消息给其他所有的进程;
  • 当进程B接收到进程A释放资源的请求,它会移除队列中任意的(Tm:A)的资源请求;
  • 当满足以下两个条件时,进程A会被分配该资源
    1)有一个(Tm:A)的请求,按照=>关系排在队列第一位;
    2)A接收到了一个时间戳大于Tm的来自所有其他进程的消息。

1.4 一个小栗子

lamport_01
在上面这幅图中,我们可以看到现在有三个进程请求临界资源,分别是P1,P2,P3。
在P2时间戳=33时,时间戳+1,P2将34写入自己的队列,P2发送request信号分别给三个进程。
lamport_02
在P3时间戳=38时,P3收到P2的request信号,将34写入自己的队列,P3时间戳+1,向P2发送时间戳为39的reply信号。
Lamport_03
在P1时间戳=40时,P1时间戳+1,P1将41写入自己的队列P1发送request信号分别给三个进程。此时P1还没有收到P2的请求信号。
Lamport_04
在P1时间戳=42时,P1收到P2的request信号,将34写入自己的队列,P1时间戳+1,向P2发送时间戳为43的reply信号。
Lamport_05
在P2收到其中一个进程的reply信号后,因为队头是自己的时间戳,所以P2进入临界区开始使用资源。
Lamport_06
在P3时间戳=42时,P3收到P1的request信号,将41写入自己的队列,P3时间戳+1,向P1发送时间戳为43的reply信号。
Lamport_07
在P2时间戳=42时,P2收到P1的request信号,将41写入自己的队列,P2时间戳+1,向P1发送时间戳为43的reply信号。
Lamport_08
在P1时间戳=48时,像其他两个进程发送release信号,并将其在本地队列中释放,也在其他队列中释放。
Lamport_09
现在我们可以通过这个时空图回顾一下上述过程。
注意到在本地时间44, P2 或许开始使用资源,因为它已经收到来自P1值为41的时间戳的消息,比P2值为34的时间戳的需求消息更大.
此算法按照“发生在先”关系的顺序授予资源(无优先级倒置).

2 算法实现

废话不多说,我直接就上代码了!

#define true    1
#define false   0
#define process_num 4//线程数目
int choosing[process_num]={false};
int number[process_num]={0};//排队签到号码

//找出最大的号码
int find_max(void)
{
    int max=0;
    for(int i=0;i<process_num;++i)
    {
        if(number[i]>max)
            max=number[i];
    }
    return max;
}

void enter_lock(int thread_id)
{
    choosing[thread_id]=true;
    number[thread_id]=find_max()+1;//选号码
    choosing[thread_id]=false;
    for(int i=0;i<process_num;++i)
    {
        while(choosing[i]);//等待其他线程选号码
        while((number[i] != 0)&&
            ( (number[i] < number[thread_id]) || ((number[i] == number[thread_id]) && (i < thread_id)) ));//阻塞,等待调度
    }
}

//释放号码
void exit_lock(int thread_id)
{
    number[thread_id]=0;//释放号码
}

3 适用领域

1.适合节点数目少且变动不频繁的系统,且由于每个程序均需通信交互,因此适合 P2P 结构的系统。
2.Hadoop 是我们非常熟悉的分布式系统,其中的分布式文件系统 HDFS 的文件修改就是一个典型的应用分布式算法的场景。

以上就是本人对于lamport算法的相关理解,如果有什么疏漏之处还请大家批评指正!

  • 10
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神仙诙谐代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值