[CareerCup] 16.4 A Lock Without Deadlocks 無死鎖的鎖

Grandyang發表於2016-04-16

 

16.4 Design a class which provides a lock only if there are no possible deadlocks.

 

有很多方法可以避免死鎖的發生,一個常用的方法是列出所需要的鎖,然後判斷鎖上這些鎖後會不會發生死鎖,比如有如下的鎖的順序:

A = {1, 2, 3, 4}

B = {1, 3, 5}

C = {7, 5, 9, 2}

這是有可能產生死鎖的,比如當A鎖上2等待3,當B鎖上3等待5,當C鎖上5等待2,我們可以將其看做圖,2連上3,3連上5,5連上2,那麼就會有環。一條邊(w,v)表示鎖上v後馬上鎖w,那麼上述裡子的圖中的邊為(1, 2), (2, 3), (3, 4), (1, 3), (3, 5), (7, 5), (5, 9), (9, 2)。那麼我們在檢測是否有死鎖的情況就是要找圖中是否存在環,我們可以用DFS來搜尋所有的相連的部分,我們用DFS需要標記點的狀態,我們首先定義個LockFactory類,用來儲存鎖的序列,比如上面的A,B,C,然後對於每一個鎖序列,我們先將所有的鎖都鏈起來,然後標記為false,然後用DFS判斷是否有環,如果有環,則斷開當前鎖序列之間的所有連線,參見程式碼如下;

 

import java.util.Hashtable;
import java.util.LinkedList;
import java.util.concurrent.locks.Lock;

public class LockFactory {
    private static LockFactory instance;
    private int numberOfLocks = 5;
    private LockNode[] locks;
    private Hashtable<Integer, LinkedList<LockNode>> lockOrder;
    
    private LockFactory(int count) {
        numberOfLocks = count;
        locks = new LockNode[numberOfLocks];
        lockOrder = new Hashtable<Integer, LinkedList<LockNode>>();
        for (int i = 0; i < numberOfLocks; ++i) {
            locks[i] = new LockNode(i, count);
        }
    }
    
    public static LockFactory getInstance() {
        return instance;
    }
    
    public static LockFactory initialize(int count) {
        if (instance == null) {
            instance = new LockFactory(count);
        }
        return instance;
    }
    
    public boolean hasCycle(Hashtable<Integer, Boolean> touchedNodes, int[] resourcesInOrder) {
        for (int resource : resourcesInOrder) {
            if (touchedNodes.get(resource) == false) {
                LockNode n = locks[resource];
                if (n.hasCycle(touchedNodes)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    public boolean declare(int ownerId, int[] resourcesInOrder) {
        Hashtable<Integer, Boolean> touchedNodes = new Hashtable<Integer, Boolean>();
        int index = 1;
        touchedNodes.put(resourcesInOrder[0], false);
        for (index = 1; index < resourcesInOrder.length; ++index) {
            LockNode pre = locks[resourcesInOrder[index - 1]];
            LockNode cur = locks[resourcesInOrder[index]];
            pre.joinTo(cur);
            touchedNodes.put(resourcesInOrder[index], false);
        }
        if (hasCycle(touchedNodes, resourcesInOrder)) {
            for (int j = 1; j < resourcesInOrder.length; ++j) {
                LockNode p = locks[resourcesInOrder[j - 1]];
                LockNode c = locks[resourcesInOrder[j]];
                p.remove(c);
            }
            return false;
        }
        LinkedList<LockNode> list = new LinkedList<LockNode>();
        for (int i = 0; i < resourcesInOrder.length; ++i) {
            LockNode resource = locks[resourcesInOrder[i]];
            list.add(resource);
        }
        lockOrder.put(ownerId, list);
        return true;
    }
    
    public Lock getLock(int ownerId, int resourceId) {
        LinkedList<LockNode> list = lockOrder.get(ownerId);
        if (list == null) return null;
        LockNode head = list.getFirst();
        if (head.getId() == resourceId) {
            list.removeFirst();
            return head.getLock();
        }
        return null;
    }
}

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LockNode {
    public enum VisitState {
        FRESH, VISITING, VISITED
    };
    private ArrayList<LockNode> children;
    private int lockId;
    private Lock lock;
    private int maxLocks;
    
    public LockNode(int id, int max) {
        lockId = id;
        children = new ArrayList<LockNode>();
        maxLocks = max;
    }
    
    public void joinTo(LockNode node) {
        children.add(node);
    }
    
    public void remove(LockNode node) {
        children.remove(node);
    }
    
    public boolean hasCycle(Hashtable<Integer, Boolean> touchedNodes) {
        VisitState[] visited = new VisitState[maxLocks];
        for (int i = 0; i < maxLocks; ++i) {
            visited[i] = VisitState.FRESH;
        }
        return hasCycle(visited, touchedNodes);
    }
    
    public boolean hasCycle(VisitState[] visited, Hashtable<Integer, Boolean> touchedNodes) {
        if (touchedNodes.containsKey(lockId)) {
            touchedNodes.put(lockId, true);
        }
        if (visited[lockId] == VisitState.VISITING) {
            return true;
        } else if (visited[lockId] == VisitState.FRESH) {
            visited[lockId] = VisitState.VISITING;
            for (LockNode n : children) {
                if (n.hasCycle(visited, touchedNodes)) {
                    return true;
                }
            }
            visited[lockId] = VisitState.VISITED;
        }
        return false;
    }
    
    public Lock getLock() {
        if (lock == null) {
            lock = new ReentrantLock();
        }
        return lock;
    }
    
    public int getId() {
        return lockId;
    }
}

public class j {
    public static void main(String[] args) {
        int[] res1 = {1, 2, 3, 4};
        int[] res2 = {1, 5, 4, 1};
        int[] res3 = {1, 4, 5};
        LockFactory.initialize(10);
        
        LockFactory lf = LockFactory.getInstance();
        System.out.println(lf.declare(1, res1));
        System.out.println(lf.declare(2, res2));
        System.out.println(lf.declare(3, res3));
        
        System.out.println(lf.getLock(1, 1));
        System.out.println(lf.getLock(1, 2));
        System.out.println(lf.getLock(1, 3));
        System.out.println(lf.getLock(1, 4));
        System.out.println(lf.getLock(2, 1));
        System.out.println(lf.getLock(2, 5));
        System.out.println(lf.getLock(2, 4));
        System.out.println(lf.getLock(3, 1));
        System.out.println(lf.getLock(3, 4));
        System.out.println(lf.getLock(3, 5));
    }
}

 

CareerCup All in One 題目彙總

相關文章