{"id":19794496,"url":"https://github.com/shuai-xie/os-semaphore-traffic-java","last_synced_at":"2025-07-03T18:33:07.328Z","repository":{"id":129530428,"uuid":"99598443","full_name":"Shuai-Xie/os-semaphore-traffic-java","owner":"Shuai-Xie","description":"大三下操作系统课设 - 交通信号灯模拟 - Java 接口","archived":false,"fork":false,"pushed_at":"2017-08-07T16:42:31.000Z","size":10,"stargazers_count":11,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-01T02:39:08.683Z","etag":null,"topics":["java","os","semaphore"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Shuai-Xie.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2017-08-07T16:34:45.000Z","updated_at":"2024-06-03T00:57:50.000Z","dependencies_parsed_at":"2023-03-25T01:32:22.629Z","dependency_job_id":null,"html_url":"https://github.com/Shuai-Xie/os-semaphore-traffic-java","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Shuai-Xie/os-semaphore-traffic-java","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2Fos-semaphore-traffic-java","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2Fos-semaphore-traffic-java/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2Fos-semaphore-traffic-java/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2Fos-semaphore-traffic-java/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Shuai-Xie","download_url":"https://codeload.github.com/Shuai-Xie/os-semaphore-traffic-java/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Shuai-Xie%2Fos-semaphore-traffic-java/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263379483,"owners_count":23457850,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["java","os","semaphore"],"created_at":"2024-11-12T07:13:26.718Z","updated_at":"2025-07-03T18:33:07.314Z","avatar_url":"https://github.com/Shuai-Xie.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"[操作系统课设 - 信号量机制 - 交通信号灯模拟](http://www.jianshu.com/p/60a831b66e89)\n\n## 四、算法设计\n### 4.1 创建问题情景\n设置南北向和东西向的交通灯，再随机生成任意数量的汽车。\n\n```java\n// 南北向和东西向各设置一个交通灯就可以\nLight northLight = new Light(North, Green, 0); // 方向，颜色，时间\nLight eastLight = new Light(East, Red, 0); // 时间不用指定，因为后面有timeCounter\n\n// 随机生成车辆信息\nCar[] cars = new Car[carNumber];\nRandom random = new Random();\nfor (int i = 0; i \u003c carNumber; i++) { // foreach不行，因为是数组初始化\n    cars[i] = new Car(random.nextInt(4), random.nextInt(timeRange) + 1);\n    // new Car(int direction, int showTime) 随机生成车辆朝向和出现时间，时间范围[1, timeRange]\n    // 在Car构造函数内部随机生成了车辆ID，即车牌号\n}\n```\n### 4.2. 数据预处理\n\n将汽车按照 direction 存入到 4 个方向队列中，存储顺序按照汽车出现时间 showTime 由小到大，稳定不稳定的排序都可以，**因为同时到达路口的汽车没有时间上先后之分，而这些同时到达的汽车正是我们需要调度的对象。**\n\n1. 汽车对象按照出现时间排序，因为出现时间是随机指定的。\n```java\n// cars数组按车辆出现时间排序的\nsortCarsByShowTime(cars);\n```\n```java\nprivate void sortCarsByShowTime(Car cars[]) {\n    // copy车辆信息\n    Car[] tmpCars = new Car[carNumber];\n    System.arraycopy(cars, 0, tmpCars, 0, cars.length);\n\n    // 对车辆信息按照出现时间排序\n    int index = 0; // 遍历cars数组\n    for (int i = 1; i \u003c= timeRange; i++) { // showTime递增\n        for (Car c : tmpCars) { // 遍历tmpCars\n            if (c.getShowTime() == i) { // 找到showTime=i的车辆\n                cars[index] = c;\n                index++;\n            }\n        }\n    }\n}\n```\n2. 汽车按照 direction 进入 4 个方向队列。\n\n```java\n// 车辆信息进队列\nQueue\u003cCar\u003e northCarsQueue = new LinkedBlockingQueue\u003c\u003e();\nQueue\u003cCar\u003e southCarsQueue = new LinkedBlockingQueue\u003c\u003e();\nQueue\u003cCar\u003e westCarsQueue = new LinkedBlockingQueue\u003c\u003e();\nQueue\u003cCar\u003e eastCarsQueue = new LinkedBlockingQueue\u003c\u003e();\nfor (Car c : cars) {\n    switch (c.getDirection()) {\n        case North:\n            northCarsQueue.add(c);\n            break;\n        case South:\n            southCarsQueue.add(c);\n            break;\n        case West:\n            westCarsQueue.add(c);\n            break;\n        case East:\n            eastCarsQueue.add(c);\n            break;\n        default:\n            break;\n    }\n}\n\n// 集合方式遍历，元素不会被移除\nSystem.out.println(\"生成的车辆信息\");\nfor (Car c : northCarsQueue) System.out.println(c);\nfor (Car c : southCarsQueue) System.out.println(c);\nfor (Car c : westCarsQueue) System.out.println(c);\nfor (Car c : eastCarsQueue) System.out.println(c);\nSystem.out.println();\n```\n\n### 4.3 信号量机制\n某一时刻的道路作为互斥信号量，影响体现在汽车实际通过十字路口的时间。\n```\n实际经过时间 \u003e= 到达路口时间\n```\n互斥信号量定义\n```java\n// 一条路双向车道，设置2个信互斥信号量集\nint[] northMutex = new int[100];\nint[] southMutex = new int[100];\nint[] westMutex = new int[100];\nint[] eastMutex = new int[100];\n```\n\n```java\n/**\n * 获取车辆实际经过十字路口的时间\n *\n * @param roadMutex   道路互斥信号量集\n * @param showTime    汽车出现时间\n * @param timeCounter 计时器\n * @return actualPassTime 车辆实际通过路口的时间\n */\nprivate int getActualPassTime(int[] roadMutex, int showTime, int timeCounter) {\n    // timeCounter-1 确保timeLower落在正确范围内，取商运算\n    int timeLower = (timeCounter - 1) / lightGreenSeconds * lightGreenSeconds + 1; // 时间下界\n\n    // 汽车出现时间 \u003c timeLower 重置出现时间，说明汽车等待到下一个绿灯\n    if (showTime \u003c= timeLower) showTime = timeLower;\n\n    if (roadMutex[showTime] == 0) { // 该时刻的道路资源未被占用，可通过，直接返回showTime，并将roadMutex[showTime]置1\n        roadMutex[showTime] = 1;\n        return showTime;\n    } else {                        // 这一时刻的道路资源已被占用了，不可通过\n        int sum = 0;\n        for (int i = showTime; i \u003c= timeCounter; i++) { // 查询roadMutex数组，看自己排在队列的第几位\n            if (roadMutex[i] == 1) { // =1 表示showTime之后的时刻的道路资源被占用\n                sum++;\n            }\n        }\n        roadMutex[showTime + sum] = 1; // 表示该车占用该一时刻的道路资源\n        return showTime + sum; // 返回实际通过时间\n    }\n}\n```\n\n1. 通过 timeCounter 求得绿灯刚开始亮的时间 timeLower（边界值划限）；\n2. 如果 showTime \u003c= timeLower，说明汽车已经等到这一个绿灯了，即该汽车没有在其出现时间所在的绿灯时间范围内通过路口，所以更新其 showTime 为 timeLower，这种情况下会使很多不同 showTime 的车辆出现时间都设为 timeLower，不过有两个原因可以证明这也是合理的：\n① 上一个交通灯没有通过的车陆陆续续（即 showTime 不同）到达路口，因为都在这个路口等，所以到下一个交通灯的时候 showTime 就一样了；\n② showTime 一样不会影响其先后关系，因为车辆已经入队列了，先后关系确定了。\n3. roadMutex[showTime] == 0 说明这一时段的道路未被占用，可以通过，该车辆通过的时候，设置 roadMutex[showTime] = 1，其他车辆在这一时刻不可同过，除非是反向的车辆，因为是双向车道，比如东向车在走，西向的也可以走；\n4. roadMutex[showTime] != 0 说明这一时段的道路已被占用，此时查询 roadMutex 数组，看自己排在队列的第几位，然后得到实际通过时间。\n\n\n### 4.4 解决问题\n- 南北向为绿灯时，东西向为红灯，南北向的汽车开始调度时，东西向的汽车等待，南北向的汽车出队列；\n- 东西向为绿灯时，南北向为红灯，南北向的汽车停止出队列，东西向的汽车开始调度；\n- 这个过程循环进行，直到所有的车辆通过了十字路口。\n\n\n```java\nint lightGreen; // 绿灯持续时间，用这个变量，是因为绿灯持续时间是慢慢减少为0的\nint timeCounter = 0; // 时间计数器，与车辆实际通过路口的时间有关\n\n// 一条路双向车道，设置2个互斥信号量集\nint[] northMutex = new int[100];\nint[] southMutex = new int[100];\nint[] westMutex = new int[100];\nint[] eastMutex = new int[100];\n\n// 4个String存储不同方向的车辆通过信息\nString northPassInfo = \"\";\nString southPassInfo = \"\";\nString westPassInfo = \"\";\nString eastPassInfo = \"\";\n\n// 只要还有车，队列就执行\nwhile (!northCarsQueue.isEmpty() || !southCarsQueue.isEmpty() ||\n        !westCarsQueue.isEmpty() || !eastCarsQueue.isEmpty()) {\n\n    // 打印时间段信息 如 1----10s\n    System.out.print((timeCounter + 1) + \"----\" + (timeCounter + lightGreenSeconds) + \"s\\t\");\n\n    // 调度车辆\n    if (northLight.getColor() == Green) {       // 南北向车辆通过十字路口\n        System.out.println(\"南北向绿灯亮\\n\");\n        lightGreen = lightGreenSeconds;\n        while (lightGreen-- \u003e 0) { // 每经过一辆车花费时间为1，每花费1的时间最多通过2辆车，因为是双向的\n            timeCounter++; // timeCounter与车辆实际通过路口的时间有关\n            northPassInfo += passOneCarInfo(northCarsQueue, northMutex, timeCounter);\n            southPassInfo += passOneCarInfo(southCarsQueue, southMutex, timeCounter);\n        }\n\n        // 打印南北向车辆通过信息\n        System.out.println(northPassInfo);\n        System.out.println(southPassInfo);\n\n        northPassInfo = \"\"; // 重置String，循环使用\n        southPassInfo = \"\";\n\n        northLight.setColor(Red); // 交通灯颜色转换\n        eastLight.setColor(Green);\n    } else {                                    // 东西向车辆通过十字路口\n        System.out.println(\"东西向绿灯亮\\n\");\n        lightGreen = lightGreenSeconds;\n        while (lightGreen-- \u003e 0) { // 每经过一辆车花费时间为1\n            timeCounter++;\n            westPassInfo += passOneCarInfo(westCarsQueue, westMutex, timeCounter);\n            eastPassInfo += passOneCarInfo(eastCarsQueue, eastMutex, timeCounter);\n        }\n\n        // 打印东西向车辆通过信息\n        System.out.println(westPassInfo);\n        System.out.println(eastPassInfo);\n\n        westPassInfo = \"\"; // 重置String，循环使用\n        eastPassInfo = \"\";\n\n        eastLight.setColor(Red); // 交通灯颜色转换\n        northLight.setColor(Green);\n    }\n}\n```\n\n通过一辆车 passOneCarInfo\n- 输出该车辆的信息和实际通过时间\n- 该车辆出队列\n\n```java\n// String存储一辆车的经过信息，便于后面结果的显示\nprivate static String passOneCarInfo(Queue\u003cCar\u003e carsQueue, int[] roadMutex, int timeCounter) {\n    String passInfo = \"\";\n    if (!carsQueue.isEmpty()) {\n        Car car = carsQueue.peek();\n        if (car.getShowTime() \u003c= timeCounter) { // 假定提前到了，在这一次绿灯亮一定可以穿行\n            passInfo = car.toString() + \"----\" + getActualPassTime(roadMutex, car.getShowTime(), timeCounter) + \"\\n\";\n            carsQueue.remove(); // 满足条件，放行一辆车\n        }\n    }\n    return passInfo; // 车辆出现信息 + 车辆经过时间\n}\n```\n\n### 4.5 测试\n设定条件\n```java\nprivate static final int timeRange = 20;   // 模拟总时长\nprivate static final int carNumber = 20;  // 车辆总数\nprivate static final int lightGreenSeconds = 10; // 交通灯显示绿色的时长\n```\n生成的车辆信息\n```\n车牌号           朝向    出现时间\n湘U·EM7P6\tNorth\t3\n赣T·5EYJA\tNorth\t13\n\n蒙A·2KX51\tSouth\t1\n黑M·LPHN8\tSouth\t7\n赣L·5TSL3\tSouth\t11\n闽P·EWZMH\tSouth\t11\n\n津G·X1J69\tWest\t2\n青F·PXF6N\tWest\t12\n苏C·L6Z7A\tWest\t12\n宁A·NTC5J\tWest\t13\n藏H·6VRJT\tWest\t15\n浙W·FYWU7\tWest\t15\n皖V·2NPLA\tWest\t17\n\n川U·LJSYS\tEast\t10\n桂F·EJEYK\tEast\t12\n赣S·GMB8C\tEast\t15\n港J·08QVC\tEast\t16\n港O·SR58D\tEast\t16\n台E·1H5IJ\tEast\t18\n蒙Y·YV5LD\tEast\t18\n```\n调度结果\n```\n1----10s\t南北向绿灯亮\n\n湘U·EM7P6\tNorth\t3----3\n\n蒙A·2KX51\tSouth\t1----1\n黑M·LPHN8\tSouth\t7----7\n\n11----20s\t东西向绿灯亮\n\n津G·X1J69\tWest\t2----11\n青F·PXF6N\tWest\t12----12\n苏C·L6Z7A\tWest\t12----13\n宁A·NTC5J\tWest\t13----14\n藏H·6VRJT\tWest\t15----15\n浙W·FYWU7\tWest\t15----16\n皖V·2NPLA\tWest\t17----17\n\n川U·LJSYS\tEast\t10----11\n桂F·EJEYK\tEast\t12----12\n赣S·GMB8C\tEast\t15----15\n港J·08QVC\tEast\t16----16\n港O·SR58D\tEast\t16----17\n台E·1H5IJ\tEast\t18----18\n蒙Y·YV5LD\tEast\t18----19\n\n21----30s\t南北向绿灯亮\n\n赣T·5EYJA\tNorth\t13----21\n\n赣L·5TSL3\tSouth\t11----21\n闽P·EWZMH\tSouth\t11----22\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuai-xie%2Fos-semaphore-traffic-java","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuai-xie%2Fos-semaphore-traffic-java","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuai-xie%2Fos-semaphore-traffic-java/lists"}