论文-分布式-并发控制-Lamport逻辑时钟

目录

前言

逻辑时钟讲解

算法类比为面包店内取号

Lamport算法的时间戳原理

Lamport算法的5个原则

举例说明

算法实现

参考文献


  • 前言

  • 在并发系统中,同步与互斥是实现资源共享的关键
  • Lamport面包店算法作为一种经典的解决并发问题的算法,它的实现原理和应用是每个探索并发控制的人必须要了解的知识点
  • Dijkstra于1965年提出的基于共享存储的临界区互斥访问问题
  • Dijkstra提出了基于对内存单元的原子性读写实现的方案
  • 然而,Lamport指出Dijkstra的方案会因为节点在临界区内失效而导致系统死锁
  • 在其于1974年发表的文章A New Solution of Dijkstra’s Concurrent Programming Problem中,Lamport提出了完全基于软件实现的解决方案,被称为“面包店算法”
  • Lamport面包店算法是一种经典的分布式系统中互斥访问共享资源的算法,用来解决多个线程并发访问一个共享的单用户资源的互斥问题,因其设计思想类似于面包店中取号排队的方式,因此被称为面包店算法
  • "面包店算法"模拟面包店内取号服务的模式,实现了先来先服务的的互斥访问
  • 这个算法也可以称为时间戳策略,或者叫做Lamport逻辑时钟
  • 逻辑时钟讲解

  • 这里先陈述一下这个逻辑时钟的内容:
  • 是一种在分布式系统中对事件进行时间戳排序的方法,在其中定义了因果关系,称为before
  • 例如,before在航班满员,航班可预订
  • 这里“事件预订”before“航班满员”,预订和满员就形成了因果关系
  • 现实世界中,确定事件预订发生在事件满员之前,需要预订发生在比满员更早的时间
  • 因果关系是一个事件(因)和第二个事件(果)之间的作用关系,其中后一个事件被认为是前一个事件的结果
  • 一般来说,一个事件是很多原因综合产生的结果,而且原因都发生在较早的时间点
  • 而在分布式系统中,有时不可能说两个事件中的一个首先发生;关系“happened before”只是系统中事件的部分排序
  • 我们用分布式系统中的事件的先后关系,用“->”符号来表示,例如:若事件a发生在事件b之前,那么a->b
  • 该关系需要满足下列三个条件:
    • 1-如果a和b是同一进程中的事件,a在b之前发生,则a->b
    • 2-如果事件a是消息发送方,b是接收方,则a->b
    • 3-对于事件a、b、c,如果有a->b,b->c,则有a->c
  • 注意,对于任何一个事件a,a->a都是不成立的,也就是说,关系->是反自反的
  • 有了上面的定义,我们也可以定义出“并发”(concurrent)的概念了:
    • 对于事件a、b,如果a->b,b->a两个都不成立,那么a和b就是并发的
  • 直观上,上面的->关系非常好理解,即“xxx在xxx之前发生”
  • 也就是说,一个系统在输入I1下,如果有a->b,那么对于这个系统的同一个输入I1,无论重复运行多少次,a也始终发生在b之前;
  • 如果在输入I1下a和b是并发的,则表示在同一个输入I1下的不同运行中,a可能在b之前,也可能在b之后,也可能恰好同时发生
  • 也就是说,并发并不是指一定同时发生,而是表示一种不确定性
  • ->和并发的概念,就是我们理解一个系统时最基础的概念之一了
  • 有了上面的概念,我们可以给系统引入时钟了
  • 这里的时钟就是lamport逻辑时钟
  • 一个时钟,本质上是一个事件到实数(假设时间是连续的)的函数
  • 这个函数将每个事件映射到一个数字,代表这个事件发生的时间
  • 形式一点来说,对于每个进程Pi,都有一个时钟Ci,这个时钟将该进程中的事件a映射到Ci(a)
  • 对于一个事件b,假设b属于进程Pj,那么C(b)=Cj(b)
  • 这里插一句,从这个定义也可以看到大师对分布式系统的理解
  • 分布式系统中不存在一个“全局”的实体
  • 在该系统中,每个进程都是一个相对独立的实体,它们有自己的本地信息(本地Knowledge)
  • 而整个系统的信息则是各个进程的信息的一个聚合
  • 有了时钟的一个“本质定义”还不够,我们需要考虑,什么样的时钟是一个有意义的,或者说正确的时钟
  • 其实,有了前文的->关系的定义,正确的时钟应满足的条件已经十分明显了:
  • 时钟条件:对于任意两个事件a,b,如果a->b,那么C(a)<C(b)
  • 注意,反过来讲这个条件可不成立
  • 如果我们要求反过来也成立,即“如果a->b为假,那么C(a)<C(b)也为假”,那就等于要求并发事件必须同时发生,这显然是不合理的
  • 结合前文->关系的定义,我们可以把上面的条件细化成如下两条:
    • 1-如果a和b是进程Pi中的两个事件,并且在Pi中,a在b之前发生,那么Ci(a)<Ci(b)
    • 2-如果a是Pi发送消息m,b是Pj接收消息m,那么Ci(a)<Cj(b)
  • 上面就定义了合理的逻辑时钟
  • 显然,一个系统可以有无数个合理的逻辑时钟
  • 实现逻辑时钟也相对简单,只要遵守两条实现规则就可以了:
    • 1-每个进程Pi在自己的任何两个连续的事件之间增加Ci值
    • 2-如果事件a是Pi发送消息m,那么在m中应该带上时间戳Tm=Ci(a);如果b是进程Pj接收到消息m,那么,进程Pj应该设置Cj为大于max(Tm,Cj(b))
  • 有了上面逻辑时钟的定义,我们现在可以为一个系统中所有的事件排一个全序,就是使用事件发生时的逻辑时钟读数进行排序,读数小的在先
  • 当然,此时可能会存在两个事件同时发生的情况
  • 如果要去除这种情况,方法也非常简单:如果a在进程Pi中,b在进程Pj中,Ci(a)=Cj(b)且i < j,那么a在b之前
  • 形式化一点,我们可以把系统事件E上的全序关系“=>”定义为:
  • 假设a是Pi中的事件,b是Pj中的事件,那么:a=>b当且仅当以下两个条件之一成立:
    • 1-Ci(a)<Cj(b)
    • 2-Ci(a)=Cj(b) 且 i < j
  • 算法类比为面包店内取号

  • Lamport把上面这些数理逻辑时钟的概念以非常直观地类比为顾客去面包店采购
  • 面包店只能接待一位顾客的采购
  • step1:已知有n位顾客要进入面包店采购,安排他们按照次序在前台登记一个签到号码;该签到号码逐次加1
  • step2:根据签到号码的由小到大的顺序依次入店购货
  • step3:完成购买的顾客在前台把其签到号码归0;如果完成购买的顾客要再次进店购买,就必须重新排队
  • 这个类比中的顾客就相当于线程,而入店购货就是进入临界区独占访问该共享资源
  • 由于计算机实现的特点,存在两个线程获得相同的签到号码的情况,这是因为两个线程几乎同时申请排队的签到号码,读取已经发出去的签到号码情况,这两个线程读到的数据是完全一样的,然后各自在读到的数据上找到最大值,再加1作为自己的排队签到号码
  • 为此,该算法规定如果两个线程的排队签到号码相等,则线程id号较小的具有优先权
  • 进入临界区
    • 已经拿到排队签到号码的线程,要轮询检查自己是否可以进入临界区
    • 即检查n个线程中,自己是否具有最小的非0排队签到号码;或者自己是具有最小的非0排队签到号码的线程中,id号最小的
    • 可以用伪代码表示上述检查:

  • 非临界区
    • 一旦线程在临界区执行完毕,需要把自己的排队签到号码置为0,表示处于非临界区
  • 把该算法原理与分布式系统相结合,即可实现分布式锁
  • 注意这个系统中需要引入时钟同步,博主的意见是可以采用SNTP实现时钟同步(非权威,仅供参考)
  • Lamport算法的时间戳原理

  • 由部分排序可知,问题的关键点在于节点间的交互要在事件发生顺序上达成一致,而不是对于时间达成一致
  • 所以,逻辑时钟指的是分布式系统中用于区分时间发生顺序的机制
  • 从某种意义上来讲,现实世界的物理时间其实是逻辑时钟的特例
  • 分布式系统中,按是否存在节点交互可分为三类事件,节点内部,发送事件,接收事件
  • 每个事件对应一个Lamport时间戳,初始值为0
  • 如果事件在节点内发生,时间戳+1
  • 如果事件属于发送事件,时间戳+1并在消息中带上该时间戳
  • 如果事件属于接收事件,时间戳=Max(本地时间戳,消息中的时间戳)+1
  • 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的来自所有其他进程的消息
  • 举例说明

  • 在下面这幅图中,我们可以看到现在有三个进程请求临界资源,分别是P1,P2,P3
  • 在P2时间戳=33时,时间戳+1,P2将34写入自己的队列,P2发送request信号分别给三个进程

  • 在P3时间戳=38时,P3收到P2的request信号,将34写入自己的队列,P3时间戳+1,向P2发送时间戳为39的reply信号

  • 在P1时间戳=40时,P1时间戳+1,P1将41写入自己的队列,P1发送request信号分别给三个进程;此时P1还没有收到P2的请求信号

  • 在P1时间戳=42时,P1收到P2的request信号,将34写入自己的队列,P1时间戳+1,向P2发送时间戳为43的reply信号

  • 在P2收到其中一个进程的reply信号后,因为队头是自己的时间戳,所以P2进入临界区开始使用资源

  • 在P3时间戳=42时,P3收到P1的request信号,将41写入自己的队列,P3时间戳+1,向P1发送时间戳为43的reply信号

  • 在P2时间戳=42时,P2收到P1的request信号,将41写入自己的队列,P2时间戳+1,向P1发送时间戳为43的reply信号

  • 在P2时间戳=48时,向其他两个进程发送release信号,并将其在本地队列中释放,也在其他队列中释放

  • 现在我们可以通过这个时空图回顾一下上述过程

  • 注意到在本地时间44,P2或许开始使用资源,因为它已经收到来自P1值为41的时间戳的消息,比P2值为34的时间戳的需求消息更大
  • 此算法按照“发生在先”关系的顺序授予资源(无优先级倒置)
  • 算法实现

  • 定义
    • 数组Choosing[i]为真,表示进程i正在获取它的排队登记号
    • 数组Number[i]的值,是进程i的当前排队登记号;如果值为0,表示进程i未参加排队,不想获得该资源;规定这个数组元素的取值没有上界
    • 正在访问临界区的进程如果失败,规定它进入非临界区,Number[i]的值置0,即不影响其它进程访问这个互斥资源
  • 代码

  • 细节讨论
    • 每个线程只写它自己的Choosing[i]、Number[i],只读取其它线程的这两个数据项
    • 这个算法不需要基于硬件的原子(atomic)操作实现,即它可以纯软件实现
    • 使用Choosing数组是必须的
    • 假设不使用Choosing数组,那么就可能会出现这种情况:
      • 设进程i的优先级高于进程j(即i<j),两个进程获得了相同的排队登记号(Number数组的元素值相等)
      • 进程i在写Number[i]之前,被优先级低的进程j抢先获得了CPU时间片,这时进程j读取到的Number[i]为0,因此进程j进入了临界区
      • 随后进程i又获得CPU时间片,它读取到的Number[i]与Number[j]相等,且i<j,因此进程i也进入了临界区
      • 这样,两个进程同时在临界区内访问,可能会导致数据腐烂(data corruption)
      • 算法使用了Choosing数组变量,使得修改Number数组的元素值变得“原子化”,解决了上述问题
    • 具体实现时,可以把上述伪代码中的忙等待(busy wait),换成交出线程的执行权,例如yield操作
  • 参考文献

  • Original Paper
  • On his publications page,Lamport has added some remarks regarding the algorithm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/119323.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker部署rabbitmq的坑

背景 今天用docker部署rabbitmq&#xff0c;启动都一起正常&#xff0c;但是当访问15672端口时&#xff0c;不能加载出页面。 排查 1.防火墙是否开启 ufw status2.ip是否能ping通 ping 192.168.x.x3.检查docker日志 docker psdocker logs -f 容器id4.进入容器&#xff0c…

Vue3项目创建+组合式API使用+组件通信+渲染微博热搜+打包上线

摘要 Vue3的组合式API大大减少了代码量&#xff0c;以及使用也方便了很多&#xff0c;本案例使用Vite创建一个Vue3示例&#xff0c;简单介绍Vue3的组合式API使用以及父传子组件传参示例。 创建Vue3项目 1、首先要安装 Node.js 下载地址&#xff1a;https://nodejs.org/en/do…

Windows安装virtualenv虚拟环境

需要先安装好python环境 1 创建虚拟环境目录 还是在D:\Program\ 的文件夹新建 .env 目录&#xff08;你也可以不叫这个名字&#xff0c;一般命名为 .env 或者 .virtualenv &#xff0c;你也可以在其他目录中创建&#xff09; 2 配置虚拟环境目录的环境变量 3 安装虚拟环境 进…

如何集成验证码短信API到你的应用程序

引言 当你需要为你的应用程序增加安全性和用户验证功能时&#xff0c;集成验证码短信API是一个明智的选择。验证码短信API可以帮助你轻松实现用户验证、密码重置和账户恢复等功能&#xff0c;提高用户体验并增强应用程序的安全性。本文将介绍如何将验证码短信API集成到你的应用…

AutoCAD 2024 Mac中文附激活补丁 兼容M1.M2电脑

AutoCAD 2024是一款功能强大的CAD设计绘图工具&#xff0c;旨在帮助用户创建和编辑高质量的设计图纸和模型。该软件支持2D和3D设计&#xff0c;具有丰富的功能和工具&#xff0c;可用于绘图、建模、注释、标注、尺寸设置等多种操作。AutoCAD 2024还引入了智能对象捕捉、实时预览…

【AGC】.p12证书文件如何获取MD5

近期在使用DevEco Studio3.1打包应用时遇到了一个问题&#xff0c;我使用Build—Generate Key and CSR创建了密钥库文件。 我这里需要获取到创建的.p12证书文件的MD5值&#xff0c;于是在控制台使用了keytool -list -v -keystore D:\myapp.p12命令获取证书指纹&#xff0c;但是…

【51单片机】:智能施工电梯系统

项目效果&#xff1a; 基于51单片机的智能施工电梯系统 摘 要 智能施工电梯系统目前广泛应用于人们建筑工程中&#xff0c;为人们施工时上下搬运提供了极大的便利。智能施工电梯系统包括密码开启、超重提示&#xff0c;电梯运作及相关信息显示等等功能&#xff0c;施工电梯为我…

ROS学习笔记——配置环境变量

重点解决&#xff1a;避免每次都source ros2环境&#xff0c;每次都要设置ros_domain_id等等设置 Background ROS 2 relies on the notion of combining workspaces using the shell environment. ros2 依赖于“组合工作区”这个改变&#xff0c;使用shell 环境来实现 …

DevOps持续集成-Jenkins(1)

文章目录 DevOpsDevOps概述Code阶段工具&#xff08;centos7-gitlab主机&#xff09;Windows下安装Git&#xff08;作用是&#xff1a;使我们可以上传代码到GitLab&#xff09;Linux下安装GitLab⭐&#xff08;作用是&#xff1a;运行一个GitLab接收代码&#xff09;环境准备先…

数据结构 C语言 2.1 线性表抽象数据类型 2.2 小议顺序表

一、线性表抽象数据类型 线性表的定义 定义&#xff1a;零个或多个数据元素的有限序列 线性表的特点&#xff1a; 1.它是一个序列 数据元素之间是有序的 数据元素之间是一对一的关系 2.有限性 线性表的数据元素个数是有限的 注意&#xff1a;零个数据元素的有限序列又…

【Qt样式(qss)-5】qss局部渲染混乱,错乱,不生效的一种原因

前言&#xff1a; 之前写过一些关于qss的文章&#xff1a; 【Qt样式&#xff08;qss&#xff09;-1】手册小结&#xff08;附例&#xff1a;软件深色模式&#xff09;_深蓝色主题qss表-CSDN博客 【Qt样式&#xff08;qss&#xff09;-2】使用小结&#xff08;软件换肤&#…

2023了,是时候使用pnpm了!

2023了&#xff0c;是时候使用pnpm了&#xff01; Excerpt 2023了&#xff0c;是时候使用pnpm了&#xff01; 什么是pnpm pnpm代表performant npm&#xff08;高性能的npm&#xff09;&#xff0c;同npm和Yarn&#xff0c;都属于Javascript包管理安装工具&#xff0c;它较npm和…

倍福控制Beckhoff_AX5000 控制第三方电机

1. 把第三方电机的.XML 文件&#xff0c;拷贝到 C:\TwinCAT\Io\TcDriveManager\MotorPool 目录下&#xff0c;并重新启动 TwinCAT。 2. 打开新的 System Manager 文件&#xff0c;完成 Choose Target 之后&#xff0c;把 TwinCAT System Manager 置为 Config mode。 3. 右击 …

【鸿蒙软件开发】ArkTS基础组件之Gauge(环形图表)、LoadingProgress(动态加载)

文章目录 前言一、Gauge环形图表1.1 子组件1.2 接口参数介绍 1.2 属性1.3 示例代码二、LoadingProgress2.1 子组件2.2 接口2.3 属性2.4 示例代码 总结 前言 Gauge&#xff1a;数据量规图表组件&#xff0c;用于将数据展示为环形图表。 LoadingProgress&#xff1a;用于显示加载…

c#使用ExifLib库提取图像的相机型号、光圈、快门、iso、曝光时间、焦距信息等EXIF信息

近期公司组织了书画摄影比赛&#xff0c;本人作为摄影爱好者&#xff0c;平时也会拍些照片&#xff0c;这次比赛当然不能错过。为了提高获奖概率&#xff0c;选了19张图像作为参赛作品。但是&#xff0c;摄影作品要提交图像的光圈、曝光时间等参数。一两张还可以通过电脑自带软…

推开科研成果落地“最后一扇门”

科研成果只有落地了&#xff0c;才能发挥出它真正的价值。虽然中国近几年已经飞速发展&#xff0c;但是我们的自主创新能力依然比不了发达国家。而且&#xff0c;尽管科研成果在理论和实践上已经取得了很大的进展&#xff0c;但如何将其落地到实际生产中仍然存在很多问题。其中…

软考高项(十二)项目质量管理 ★重点集萃★

&#x1f451; 个人主页 &#x1f451; &#xff1a;&#x1f61c;&#x1f61c;&#x1f61c;Fish_Vast&#x1f61c;&#x1f61c;&#x1f61c; &#x1f41d; 个人格言 &#x1f41d; &#xff1a;&#x1f9d0;&#x1f9d0;&#x1f9d0;说到做到&#xff0c;言出必行&am…

kafka3.X集群安装(不使用zookeeper)

一、kafka集群实例角色规划 在本专栏的之前的一篇文章《kafka3种zk的替代方案》已经为大家介绍过在kafka3.0种已经可以将zookeeper去掉。 上图中黑色代表broker&#xff08;消息代理服务&#xff09;&#xff0c;褐色/蓝色代表Controller(集群控制器服务) 左图&#xff08;kafk…

字节码进阶之JVM Attach API详解

字节码进阶之JVM Attach API详解 文章目录 字节码进阶之JVM Attach API详解附加到虚拟机加载代理和获取信息分离虚拟机 使用Attach API的基本步骤1. **获取虚拟机实例**&#xff1a;2. **附加到虚拟机**&#xff1a;3. **加载代理或获取信息**4. **从虚拟机分离**&#xff1a;…

C++初阶1

目录 介绍&#xff1a; 一&#xff0c;命名空间 1-1&#xff0c;命名空间的定义 1-2&#xff0c;命名空间的使用 1-3&#xff0c;C标准官方命名空间 二&#xff0c;缺省参数 2.1&#xff0c;缺省参数分类 三&#xff0c;函数重载 四&#xff0c;引用 4-1&#xff0c;…