BUAAOO_UnitTwo

table of Contents

1. Design strategy

  • First homework
  • Second job
  • Third homework

Second, the third job scalability analysis-SOLID principle as an example

3. Metric analysis

  • First homework
  • Second job
  • Third homework

4. Bug analysis

V. Hack strategy

6. Experience

 

introduction

  The three assignments in the second unit are iterative thinking about the elevator problem. This unit is our first study and contact with multi-threaded problems. The focus of the investigation in the multi-threading problem is the possession and release of locks. If they are not handled properly, they will easily cause deadlocks. At the same time, due to the uncertainty of multi-threaded operation, the difficulty of writing code and debugging is greatly increased.

 

1. Design strategy

First homework

  • The first operation was a single elevator that can be slightly dispatched. I used the consumer-producer model in this operation.
  • First build a tray class Tray, a producer thread InputProducer, and a consumer thread ElevatorConsumer, the idea is basically the same as the example in class.
  • Although I built the Controller class to complete the function of the scheduler in this assignment, due to poor design considerations, most of the final scheduling is still implemented by the elevator itself.
  • My scheduling strategy is to use queue to store all the requests received by the pallet, and to use Elevator's internal request to store the request being executed in the elevator. Every time it reaches the first floor, the request is analyzed first, and if desti == floor, it is dropped off , After sleep door opening and closing time, and then analyze the queue, if from == floor then visit.
  • I chose to drop off immediately when the elevator arrived, and to take classes at the moment the elevator was closing the door, in order to receive as many passengers as possible.
  • My scheduling performance is acceptable. Now I want to improve the selection of the main demand and set it to the longest path instead of simply taking the head;

Second job

  • The second operation is a simple extension of the first operation, which changes the number of elevators to 1-5 indefinitely and sets a maximum passenger limit.
  • I still adopted the basic idea of ​​the first job, after processing the first elevator number input, return to the main function, and then decide the elevator that needs to start.
  • My scheduling strategy is to distribute all the received requests to the starting elevator. The specific operation is to take the modulus of the request serial number and divide it into different elevator trays according to the remainder to wait for processing. The remaining steps are almost the same as the first job.
  • First instantiate the tray Tray class 5 times to correspond to the list of pending requests for different elevators (even if some are not necessarily used); in the input thread InputHandler are divided into different elevators in sequence; the Elevator class is based on the first job Add a maxnum attribute to indicate the maximum passenger capacity. During the passenger process, you need to pay attention to the changes in the passenger capacity. Once you are full, you will not be passengers.
  • It should be noted that it is still necessary to disembark and then board to increase the number and efficiency of passengers.
  • The scheduling performance was average. Before I chose this sharing strategy, I tried the elevator to grab customers according to the situation. In the end, I still caused a lot of bugs due to the inadequate processing of multi-threading. I chose the average performance. But the strategy of correctness and stability.

Third homework

  • On the basis of the second operation, the elevators are divided into three categories, each of which has different lifting times, maximum number of passengers and elevator landing floors. In addition to the passenger boarding request, a request to add a specific elevator has been added to the input.
  • I didn't write this job in the same way as the previous two jobs. Instead, I rewritten the scheduler class Controller, and still created the InputHandler input thread and Elevator elevator thread. The request to add an elevator started a new thread in the InputHandler thread.
  • The transfer strategy I used this time is to determine which type of elevator parking floor the passenger request from and desti belong to, and then divide the request into from-intermediate floor and intermediate floor-desti. The intermediate floor of the transfer needs to be based on The specific situation is selected, for example, from requests belonging to category A, desti belonging to category B, the middle floor can choose 1 or 15 according to the distance, BC category can choose 1 or 5, and so on.
  • If there is a new elevator, a random number is set to divide the request into the original elevator and the new elevator of the same kind.
  • The performance of this dispatch is acceptable. Now it seems that the following allocation request can be improved. It is not simply divided, but divided into the pending requests of the closer elevator according to the distance.

 

Second, the scalability analysis of the third operation-SOLID principle as an example

  1. SRP single function principle:
    • Separate the functions of elevator thread, producer thread and scheduler thread, and perform their respective duties, basically satisfy the principle of single function;
    • The producer thread is only responsible for reading passenger requests and new requests and adding them to the corresponding global queue;
    • The elevator thread is responsible for getting the request from the dispatcher and running the request;
    • The scheduler thread is responsible for distributing to different elevator request queues according to the request;
    • 如要对第三次作业继续进行扩展设计,那么这几个类的主要功能代码依然可以复用,因此这一设计是可扩展的。
  2. OCP开闭原则:LSP里氏替换原则:未使用继承。
    • 前两次作业的调度职责主要由电梯负责,第三次作业分出了对应的调度器线程,这部分工作几乎是从头做起的,可见前两次作业中没有满足这一原则的要求,仍然面临了重构的问题。
    • 若要对第三次作业进行复用,可能需要对调度器的调度算法进行改进,除此之外应该不会存在大的改动,也是可以扩展的。
  3. LSP里氏替换原则:未使用继承。
  4. ISP接口隔离原则:未使用接口。
  5. DIP依赖反转原则:未使用抽象类。

 

三、度量分析

第一次作业

  • UML类图

      

  • 复杂度分析

      

      

      

  • 优缺点点评:
    • 优点:各个类的分工较为明确;
    • 缺点:可以看出controller类和电梯类的复杂度过高,本次作业中电梯确实承担了过多的指责,而没有完全发挥调度的作用。
  • UML时序图

 

 

第二次作业

  • UML类图

 

  • 复杂度分析

  • 优缺点
    • 基本上复用了上一次的代码,做到了程序的可扩展;
    • 电梯类仍然承担着过多职责,因此复杂度很高;
    • 由于实行分摊策略,因此需要在输入线程中将请求加至不同托盘里,因此也有复杂度过高问题。
  • UML时序图

 

第三次作业

  • UML类图

 

  • 复杂度分析

  • 优缺点:
    • 真正做到了调度器指责与电梯职责的分开;
    • 输入线程中由于还增加了新增电梯的请求,因此复杂度比较高;
    • 调度器和电梯线程都存在复杂度过高的问题,想来是我的很多功能的实现出现了代码重复、职责分区不明等问题。
  • UML时序图

 

四、Bug分析

  • 第一次作业强测与互测均未出现bug;本地刚开始中测时,出现过WA和超时等问题,分析后发现是自己对于多线程理解不到位,导致一些wait和notify命令用错,均已改正。
  • 第二次作业强测与互测均未出现bug。
  • 第三次作业强测和互测中都出现了玄学的WA,提示是乘客State问题,本地进行多次测试都未复现,无奈之下一字不改交上去debug,又都AC了,经了解不少同学也都有这样的情况,想来多线程确实容易出现线程不安全的情况,而我的程序在某些情况下可能会出现不稳定的运行结果。

五、Hack策略

  • 第一次作业未能成功hack;
  • 第二次作业hack到两位同学WA和RTLE问题,第一位同学的WA报错和我之后遇到的情况很类似,恐怕也是线程运行结果不稳定导致的,第二位同学的RTLE可能与调度策略有关,在极端情况下可能会超时。
  • 第三次作业未能成功hack;
  • 多线程作业的调试难度很大,我在本单元的hack中主要采用的是手动构造测试数据集的方法。

六、心得与体会

  本单元的电梯调度作业让我对多线程相关知识有了较为深入的了解。刚写第一次作业时觉得很无从下手,主要是没能很快的把刚学的多线程知识立马运用到实际应用中去,所以导致了第一次作业设计和架构上的不完善(例如没能实现完整的调度器功能),第二次作业时其实完全有时间完善一下第一次作业的构造,但发现均摊思想几乎不用动之前的构造时,还是摸鱼了(下场就是扬了性能分)。第三次作业由于电梯种类发生变化,这才不得不写出了完整的调度。每一单元的第一次作业还是尽量要完善自己的代码做到功能分开,并留出可扩展的空间。

       我对线程安全的理解是:当多个线程访问共享变量时,要通过对象锁和wait、notify方法做到一个对象在同步块内只能被一个线程访问;此外还要避免轮询问题,防止出现CPU超时。

       感谢讨论区同学慷慨分享的知识与见解,也感谢研讨课上不少同学分享出的专题研讨,这些都给了我不少的启发和收获。

 

Guess you like

Origin www.cnblogs.com/HildaChen-/p/12709698.html