lamport麪包店算法簡介

Lamport麪包店算法是解決多個線程併發訪問一個共享的單用戶資源的互斥問題的算法。由萊斯利·蘭波特發明。git

算法類比

Lamport把這個併發控制算法很是直觀地類比爲顧客去麪包店採購。github

  • 麪包店一次只能接待一位顧客的採購。
  • 已知有n位顧客要進入麪包店採購,按照次序安排他們在前臺登記一個簽到號碼。該簽到號碼逐次增長1。
  • 顧客根據簽到號碼的由小到大的順序依次入店購貨。
  • 完成購買的顧客在前臺把其簽到號碼歸0。若是完成購買的顧客要再次進店購買,就必須從新排隊。

這個類比中的顧客就至關於線程,而入店購貨就是進入臨界區獨佔訪問該共享資源。因爲計算機實現的特色,存在兩個線程得到相同的簽到號碼的狀況,這是由於兩個線程幾乎同時申請排隊的簽到號碼,讀取已經發出去的簽到號碼狀況,這兩個線程讀到的數據是徹底同樣的,而後各自在讀到的數據上找到最大值,再加1做爲本身的排隊簽到號碼。算法

爲此,該算法規定若是兩個線程的排隊簽到號碼相等,則線程id號較小的具備優先權。併發

原理

Lamport時間戳原理以下:分佈式

  • 每一個事件對應一個Lamport時間戳,初始值爲0
  • 若是事件在節點內發生,時間戳加1
  • 若是事件屬於發送事件,時間戳加1並在消息中帶上該時間戳
  • 若是事件屬於接收事件,時間戳 = Max(本地時間戳,消息中的時間戳) + 1

5個原則

  • 爲了請求資源,進程A發送消息(Tm:A)給全部的其餘進程,而且把這個消息放到進程隊列中,Tm是消息的時間戳
  • 當進程B接收到了進程A的(Tm:A)請求後,會把它放到本身的請求隊列,而後發送一個帶時間戳的確認消息給A
  • 爲了釋放資源,進程A移除全部(Tm:A)的請求消息,而後發送帶時間戳的A釋放資源請求消息給其餘全部的進程
  • 當進程B接收到進程A釋放資源的請求,它會移除隊列中任意的(Tm:A)的資源請求
  • 當知足如下兩個條件時,進程A會被分配該資源:ui

    • a)有一個(Tm:A)的請求,按照=>關係排在隊列第一位;
    • b)A接收到了一個時間戳大於Tm的來自全部其餘進程的消息

代碼示例

private void processRevcMsg(Message m) throws InterruptedException {
        // 原理4 若是事件屬於接收事件,時間戳 = Max(本地時間戳,消息中的時間戳) + 1
        clock.update(m.getTimestamp());
        lastSendMap.put(m.getFrom(), m);
        switch (m.getMsgType()) {
            case REQUEST_RES:
                // rule 2 當進程B接收到了進程A的(Tm:A)請求後,會把它放到本身的請求隊列,而後發送一個帶時間戳的確認消息給A
                addMessageToReqMap(m);
                Message ackMsg = new Message(pid, m.getMsgId(), MessageType.REQUEST_ACK, clock.time());
                // send ack to sender
                sendToTargetProcess(ackMsg,m.getFrom());
                break;
            case REQUEST_ACK:
                break;
            case RELEASE_RES:
                // rule 4 當進程B接收到進程A釋放資源的請求,它會移除隊列中任意的(Tm:A)的資源請求
                dropMessageFromReqMap(m);
                break;
            default:
                break;
        }
        tryToAcquireResource();
    }

    private void tryToAcquireResource() {
        synchronized (reqMap) {
            if(!reqMap.containsKey(pid) || reqMap.get(pid).isEmpty()){
                return ;
            }

            Message myMessage = reqMap.get(pid).get(0);
            int acceptCount = 1;

            // rule 5 當知足如下兩個條件時,進程A會被分配該資源:a)有一個(Tm:A)的請求,按照=>關係排在隊列第一位;b)A接收到了一個時間戳大於Tm的來自全部其餘進程的消息

            // condition (ii) of rule 5
            // A接收到了一個來自全部其餘進程的消息,並且時間戳大於Tm
            for (Map.Entry<Integer, Message> entry : lastSendMap.entrySet()) {
                if (entry.getKey() == pid) {
                    continue;
                }
                if (isFirstEarlier(myMessage, entry.getValue())) {
                    acceptCount++;
                }else{
                    return ;
                }
            }
            if (!coordinator.hasAcceptedAll(acceptCount)){
                return;
            }

            // condition (i) of rule 5
            // 有一個Tm:A的請求,按照=>關係排在隊列第一位
            for (Map.Entry<Integer, List<Message>> entry : reqMap.entrySet()) {
                if (entry.getKey() != pid && !entry.getValue().isEmpty()) {
                    if (!isFirstEarlier(myMessage, entry.getValue().get(0))) {
                        return;
                    }
                }
            }

            // remove this request message
            final Message firstMsg = reqMap.get(pid).remove(0);
            workingPool.execute(new Runnable() {
                public void run() {
                    coordinator.acquire(firstMsg.getMsgId(), pid, firstMsg.getTimestamp());
                    // emulate owning resources for a long time
                    try {
                        Thread.sleep(50L);
                        // rule 3 爲了釋放資源,進程A移除全部(Tm:A)的請求消息,而後發送帶時間戳的A釋放資源請求消息給其餘全部的進程程
                        coordinator.release(firstMsg.getMsgId(), pid, firstMsg.getTimestamp());
                        Message releaseMsg = new Message(pid, firstMsg.getMsgId(),MessageType.RELEASE_RES, clock.time());
                        sendToOtherProcesses(releaseMsg);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            });
        }
    }

doc

相關文章
相關標籤/搜索