📜  门| GATE-CS-2004 |问题 21(1)

📅  最后修改于: 2023-12-03 15:28:42.289000             🧑  作者: Mango

门| GATE-CS-2004 |问题 21

这是一道GATE-CS-2004的考题,考察的是关于并发编程的知识,下面将会对该问题进行详细介绍和分析。

问题描述

某市政中央公园的入口和出口都装有转门。拜访者在入口部分向门内传送一个硬币,触发转门的开启动作,然后继续工作——如果他使用的硬币是指定的硬币。一旦一个访问者在门上打印了自己的指纹,他的护照上会被附加一个标记作为有效的拜访者并允许离开。门可以同时容纳10个有资格的人被容纳在等着通过或离开。如果有超过10个参观者在等候,其他的访问者必须等待,直到有人通过。离开门由一个类似于进门的机制控制;在离开时,访问者再次送出硬币,并再次打印自己的指纹。门将清理每个过程中的未确认的参观者。

请设计一个并发控制方案,使这个门满足这样的规则:

  1. 如果一个人已经打印了他的指纹,并试图再进入,门应该禁止进入并拒绝离开。
  2. 任何一个正在等待进门的参观者必须等到他的指纹被验证之前,才能再离开门。
解答

为了实现该控制方案,我们需要设计一个管理门的类,这个类需要控制一些重要资源,如门本身、能够通过的人数、正在等待进门的人数等。同时,还需要保证并发控制。

下面是可能的类设计和实现,注释对应着代码:

class DoorManager {
    private int numVisitorsInside; // 当前门内已经通过的游客人数
    private int numVisitorsAllowed; // 可以同时容纳的游客最大人数
    private int numVisitorsWaiting; // 正在等待进入门内的游客总数
    private Object doorLock; // 门锁,用于控制并发
    private ArrayList<Integer> fingerprints; // 已经通过门的游客的指纹数据,仅限于进入门的人员

    public DoorManager(int maxCapacity) {
        numVisitorsInside = 0;
        numVisitorsAllowed = maxCapacity;
        numVisitorsWaiting = 0;
        doorLock = new Object();
        fingerprints = new ArrayList<>();
    }

    public boolean enterGate(int fingerprint) {
        synchronized (doorLock) { // 可重入锁,确保并发控制
            if (fingerprints.contains(fingerprint)) { // 判断是否已经进入过门
                return false; // 如果已经进入过门,则无法再次进入门
            }
            if (numVisitorsInside >= numVisitorsAllowed) { // 如果门内已经有人数超过了门的能力
                numVisitorsWaiting++; // 将等候人数+1,等到有人出门再重新计算
                try {
                    doorLock.wait(); // 等待信号
                } catch (InterruptedException e) {}
            }
            numVisitorsInside++; // 注册入门
            fingerprints.add(fingerprint);
            return true; // 允许进入门
        }
    }

    public boolean exitGate(int fingerprint) {
        synchronized (doorLock) { // 可重入锁
            if (!fingerprints.contains(fingerprint)) { // 如果没有记录该游客进门的指纹
                return false; // 无法结束这次入门,也就无法出门
            }
            fingerprints.remove(new Integer(fingerprint)); // 移除指纹信息
            numVisitorsInside--; // 减去门内人数
            if (numVisitorsInside < numVisitorsAllowed && numVisitorsWaiting > 0) {
                numVisitorsWaiting--; // 有等候中的游客进入了,将等候人数-1
                doorLock.notify(); // 通知等待中的游客进门
            }
            return true; // 允许出门
        }
    }
}

上述代码可在多线程环境下安全执行,并允许遵守上述规则的访问控制。请确保按照上述指南在单元测试中验证实现,以确保其正确性。