论文-分布式-并发控制-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
相关文章:

论文-分布式-并发控制-Lamport逻辑时钟
目录 前言 逻辑时钟讲解 算法类比为面包店内取号 Lamport算法的时间戳原理 Lamport算法的5个原则 举例说明 算法实现 参考文献 前言 在并发系统中,同步与互斥是实现资源共享的关键Lamport面包店算法作为一种经典的解决并发问题的算法,它的实现原…...

长三角实现区块链电子医疗票据互联互通,蚂蚁链提供技术支持
10月25日,记者从浙江省财政厅发布的消息获悉,上海、浙江、江苏和安徽三省一市基于蚂蚁链实现区块链电子医疗票据互联互通,商业保险理赔作为首个规模化应用场景正式落地,蚂蚁保“安心赔”理赔服务率先接入。 今后,老百…...

Redis快速上手篇(三)(事务+Idea的连接和使用)
Redis事务 可以一次执行多个命令,本质是一组命令的集合。一个事务中的 所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞。 单独的隔离的操作 官网说明 https://redis.io/docs/interact/transactions/ MULTI、EXEC、…...

Spring三级缓存解决循环依赖问题
文章目录 1. 三级缓存解决的问题场景2. 三级缓存的差异性3. 循环依赖时的处理流程4. 源码验证 1. 三级缓存解决的问题场景 循环依赖指的是在对象之间存在相互依赖关系,形成一个闭环,导致无法准确地完成对象的创建和初始化;当两个或多个对象彼…...

Unity 中使用波浪动画创建 UI 图像
如何使用 只需将此组件添加到画布中的空对象即可。强烈建议您将此对象放入其自己的画布/嵌套画布中,因为它会弄脏每一帧的画布并导致重新生成整个网格。 注意:不支持切片图像。 using System.Collections.Generic; using UnityEngine; using UnityEng…...

支付功能测试用例测试点?
支付功能测试用例测试点是指在测试支付功能时,需要关注和验证的各个方面。根据不同的支付场景和需求,支付功能测试用例测试点可能有所不同,但一般可以分为以下几类: 功能测试:主要检查支付功能是否符合设计和业务需求…...

HFS 快速搭建 http 服务器
HFS 是一个轻量级的HTTP 服务工具,3.0版本前进提供Windows平台安装包,3.0版本开提供Linux和macOS平台的安装包。 HFS更适合在局域网环境中搭建文件共享服务或者安装配置源服务器。 甲 非守护进程的方式运行 HFS (Ubuntu 22.04) 一…...

学生专用台灯怎么选?双十一专业学生护眼台灯推荐
台灯应该是很多家庭都会备上一盏的家用灯具,很多大人平时间看书、用电脑都会用上它,不过更多的可能还是给家中的小孩学习、阅读使用的。而且现在的孩子近视率如此之高,这让家长们不得不重视孩子的视力健康问题。那么孩子学习使用的台灯应该怎…...

Go 常用标准库之 fmt 介绍与基本使用
Go 常用标准库之 fmt 介绍与基本使用 文章目录 Go 常用标准库之 fmt 介绍与基本使用一、介绍二、向外输出2.1 Print 系列2.2 Fprint 系列2.3 Sprint 系列2.4 Errorf 系列 三、格式化占位符3.1 通用占位符3.2 布尔型3.3 整型3.4 浮点数与复数3.5 字符串和[]byte3.6 指针3.7 宽度…...

antv/x6 导出图片方法exportPNG
antv/x6 导出图片方法exportPNG antv/x6 版本如下: "antv/x6": "2.14.1","antv/x6-plugin-export": "2.1.6",在文件中导入 import { Graph, Shape, StringExt } from antv/x6 import { Export } from antv/x6-plugin-exp…...

Decomposed Meta-Learning for Few-Shot Named Entity Recognition
原文链接: https://aclanthology.org/2022.findings-acl.124.pdf ACL 2022 介绍 问题 目前基于span的跨度量学习(metric learning)的方法存在一些问题: 1)由于是通过枚举来生成span,因此在解码的时候需要额…...

C++经典面试题:内存泄露是什么?如何排查?
1.内存泄露的定义:内存泄漏简单的说就是申请了⼀块内存空间,使⽤完毕后没有释放掉。 它的⼀般表现⽅式是程序运⾏时间越⻓,占⽤内存越多,最终⽤尽全部内存,整个系统崩溃。由程序申请的⼀块内存,且没有任何⼀…...

Hadoop+Hive+Spark+Hbase开发环境练习
1.练习一 1.数据准备 在hdfs上创建文件夹,上传csv文件 [rootkb129 ~]# hdfs dfs -mkdir -p /app/data/exam 查看csv文件行数 [rootkb129 ~]# hdfs dfs -cat /app/data/exam/meituan_waimai_meishi.csv | wc -l 2.分别使用 RDD和 Spark SQL 完成以下分析…...

使用Spring Boot限制在一分钟内某个IP只能访问10次
有些时候,为了防止我们上线的网站被攻击,或者被刷取流量,我们会对某一个ip进行限制处理,这篇文章,我们将通过Spring Boot编写一个小案例,来实现在一分钟内同一个IP只能访问10次,当然具体数值&am…...

ES 数据迁移最佳实践
ES 数据迁移最佳实践与讲解 数据迁移是 Elasticsearch 运维管理和业务需求中常见的操作之一。以下是不同数据迁移方法的最佳实践和讲解: 一、数据迁移需求梳理 二、数据迁移方法梳理 三、各方案对比 方案 优点 缺点(限制) 适用场景 是否有…...

C++中低级内存操作
C中低级内存操作 C相较于C有一个巨大的优势,那就是你不需要过多地担心内存管理。如果你使用面向对象的编程方式,你只需要确保每个独立的类都能妥善地管理自己的内存。通过构造和析构,编译器会帮助你管理内存,告诉你什么时候需要进…...

Linux硬盘大小查看命令全解析 (linux查看硬盘大小命令)
Linux操作系统是一款广泛应用于服务器和嵌入式设备的操作系统,相比于Windows等其他操作系统,Linux的优点之一就是支持强大的命令行操作。在日常操作中,了解和掌握一些简单但实用的命令可以提高工作效率。比如硬盘大小查看命令,在L…...

什么是供应链金融?
一、供应链金融产生背景 供应链金融兴起的起源来自于供应链管理一个产品生产过程分为三个阶段:原材料 - 中间产品 - 成产品。由于技术进步需求升级,生产过程从以前的企业内分工,转变为企业间分工。那么整个过程演变了如今的供应链管理流程&a…...

Qt之实现支持多选的QCombobox
一.效果 1.点击下拉列表的复选框区域 2.点击下拉列表的非复选框区域 二.实现 QHCustomComboBox.h #ifndef QHCUSTOMCOMBOBOX_H #define QHCUSTOMCOMBOBOX_H#include <QLineEdit> #include <QListWidget> #include <QCheckBox> #include <QComboBox>…...

【UI设计】Figma_“全面”快捷键
目录 1.快捷键与键位(mac与windows)2.基础快捷键3.操作区快捷键3.1视图3.2文字3.3选项3.4图层3.5组件 4.特殊技巧 Figma 是一个 基于浏览器 的协作式 UI 设计工具。【https://www.figma.com/】 Figma Sketch(UI 设计) InVision&a…...

计算机网络(谢希仁)第八版课后题答案(第一章)
1.计算机网络可以向用户提供哪些服务 连通性:计算机网络使上网用户之间可以交换信息,好像这些用户的计算机都可以彼此直接连通一样。 共享:指资源共享。可以是信息、软件,也可以是硬件共享。 2.试简述分组交换的要点 采用了存储转发技术。把报文(要发…...

argparse模块介绍
argparse是一个Python模块:命令行选项、参数和子命令解析器。argparse 模块可以让人轻松编写用户友好的命令行接口。程序定义了所需的参数,而 argparse 将找出如何从 sys.argv (命令行)中解析这些参数。argparse 模块还会自动生成…...

分布式、集群、微服务
分布式是以缩短单个任务的执行时间来提升效率的;而集群则是通过提高单位时间内执行的任务数来提升效率。 分布式是指将不同的业务分布在不同的地方。 集群指的是将几台服务器集中在一起,实现同一业务。 分布式中的每一个节点,都可以做集群…...

Android Studio的debug和release模式及签名配置
Android Studio的两种模式及签名配置 使用Android Studio 运行我们的app,无非两种模式:debug和release模式。 https://www.cnblogs.com/details-666/p/keystore.html...

【深蓝学院】手写VIO第8章--相机与IMU时间戳同步--笔记
0. 内容 1. 时间戳同步问题及意义 时间戳同步的原因:如果不同步,由于IMU频率高,可能由于时间戳不同步而导致在两帧camera之间的时间内用多了或者用少了IMU的数据,且时间不同步会导致我们首尾camera和IMU数据时间不同,…...

【Java集合类面试二十一】、请介绍TreeMap的底层原理
文章底部有个人公众号:热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享? 踩过的坑没必要让别人在再踩,自己复盘也能加深记忆。利己利人、所谓双赢。 面试官:请介绍TreeMap的底层原理…...

Go语言Channel
在本教程中,我们将讨论Channel以及 Goroutines 如何使用Channel进行通信。 什么是Channel Channel可以被认为是 Goroutine 用来进行通信的管道。与水在管道中从一端流向另一端的方式类似,可以使用Channel从一端发送数据并从另一端接收数据。 声明Chan…...

java 编译 引用 jar 包进行编译和执行编译后的class文件
编译java文件 javac -encoding UTF-8 -Djava.ext.dirs./ -d . ./FtpTest.java 执行编译class文件 java -Djava.ext.dirs./ com.util.FtpTest com.util为包路径...

Linux系统之部署Tale个人博客系统
Linux系统之部署Tale个人博客系统 一、Tale介绍1.1 Tale简介1.2 Tale特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本 四、部署Tale个人博客系统4.1 下载Tale源码4.2 查看Tale源码目录4.3 查看安装脚本内…...

【跟小嘉学 Rust 编程】三十三、Rust的Web开发框架之一: Actix-Web的基础
系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…...