OO 5th to 7th homework summary

 Homework 5 - Multithreaded Elevator

Design Framework - UML Collaboration Sequence Diagram

(If you want to see the big picture, crtl+wheel is more convenient)

Why don't I use UML Collaboration Diagram (Communication Diagram), but UML Sequence Diagram (Sequence Diagram).

On the one hand, such horizontal and vertical diagrams are more intuitive and beautiful. On the other hand, the use of Eclipse's plantUML plug-in can be more convenient to generate sequence diagrams. Although the difference between the two:

Sequence diagram mainly focuses on the time sequence of message passing between objects,
while collaboration diagram expresses the interaction process between objects and the relationship between objects.

The collaboration diagram seems to be able to better describe the cooperation relationship between threads, but I found that some software can automatically generate the collaboration diagram from the sequence diagram, which means that the two essentially describe the same thing, but the angle of communication is different. the focus. I believe that you are smart and you must be able to see the problem from multiple angles hehehe~

[Insert a piece of eclipse's plantUML plug-in installation and use] - from  http://www.importnew.com/24706.html

1. Install:

The PlantUML for Eclipse plugin is primarily used to use PlantUML in Eclipse. Install in the Eclipse plug-in market, click Help --> Install new software --> add --> Start a handsome name, enter the URL in location: http://plantuml.sourceforge.net/updatesitejuno/   --> Others installation operation

2. Click "Window/Show View/Other.." to display the PlantUML preview window panel.

Then I figured it out myself and did it: right-click the project in eclipse --> New --> Untitled Text File (that is, create a txt under the project folder).

By writing code in txt according to a certain syntax, you can see the corresponding timing diagram in the PlantUML preview window in real time. like this:

3. So what is the syntax for writing code? Super easy!

Official tutorial document (Chinese):

http://translate.plantuml.com/zh/PlantUML_Language_Reference_Guide_ZH.pdf

 [Interlude is over, back to the topic]

My multithreaded elevator UML timing diagram:

Total number of threads: main thread Main + input processing InputHandler + main scheduler MainScheduler + slave scheduler SubScheduler * 3 = 6 threads

(Note: There are a total of 4 request queues, one large and 3 small are belonging to 3 elevators)

  • Main thread: start other threads.
  • Input Processor: Constantly accepts console input, analyzes it, and if valid, puts the request into the request queue.
  • Main scheduler: Constantly scan the request queue for requests. Determine if it is a homogeneous request, delete if it is, if not: determine whether it can be piggybacked by a certain elevator, if it is, select an elevator that can be piggybacked and throw the request to it, if not: find the elevator with the least amount of movement and put the request to it. Throw this hot request to it.
  • From the scheduler: constantly check the situation of the small queue of the elevator under its jurisdiction and the situation of the elevator, to decide and notify the next action of the elevator, etc.

Design class diagram

With the design framework, it is further refined into a design class diagram: (I manually deleted and shifted)

 

 Program Metrics Analysis - Metrics

Where is the cyclomatic complexity?

 

Where is the depth of nested blocks? 

 

Unsurprisingly... I didn't think about so many design tradeoffs when I wrote this assignment, I just wanted to make it out... So I ignored the packaging and the division of functions.

Then I opened the code and found out how it was so ugly before.

  • The outline of the main scheduler is this:

  • Slave schedulers and input handlers are a bit better than that. There are also some small methods in the elevator that are > shaped... 

thread safety considerations

  • While the 3 small request queues are unique to the 3 elevators and will only be used by the slave scheduler, the large request queue is an object shared by the input processor thread and the master scheduler thread, so I would request all modifications to the queue class or The methods for reading the contents of the queue are all set as synchronous methods. (Thinking about it this way, should the queue of the elevator be made another queue class that does not require synchronization to improve a little bit of efficiency?)
  • The 3 elevators are the objects shared by the master scheduler and the slave scheduler, so I set all the methods of modifying or reading elevator information in the elevator class as synchronous methods.
  • At that time, I was still relatively young, and I was still not at ease, and synchronized some code blocks in the run methods of the four schedulers.

Self-Assessment of Strengths and Weaknesses and Reflection on Design Principles

  • Advantages: Not invalid. The overall framework is fairly clear and logical.
  • Disadvantages: (1) The implementation of the details did not consider simplification, but just wanted to do it... So it was a bit complicated, resulting in more loopholes in the impetuous class. (2) The main scheduler does a lot of things, and the judgment homogeneous request should be placed in the input processor or request queue. (3) The functions are not divided and refined, resulting in the existence of several large methods, which are not readable and maintainable.
  • Reflect on the design principles: (1) The biggest problem: the responsibility of the method is not single enough and not precise enough, that is, it violates the SRP principle and the principle of balanced distribution of responsibilities. (2) Enumeration classes, global static variables, etc. are not used, which does not conform to the principle of explicit expression. (3) High-level modules directly depend on low-level modules rather than abstraction, that is, the DIP principle is not considered.

Bug Analysis

  • Debugging after class: (1) No enumeration class is used and == is used directly when judging whether the strings are the same, I am really =.=, and this is the case in many places, and one of them forgot to change it The test point with a weight of 5 that has not been tested is really heartbreaking. (2) In the change of the main request from nothing to nothing, from one to another, that is, the upgrade of the unfinished piggyback request to the main request, it has become more complicated in a hurry, and there are some bug, and then I calm down and rewrite it again.
  • Public beta: The test point with a weight of 5 that has not been beta tested is really heartbreaking.
  • Mutual testing: Our side is safe and the other side is perfect.
  • I have grown up.
  • By the way, I would like to thank a wave of laj children for their trust in me!

 


 

Homework 6 - IFTTT Monitor

Design Framework - UML Sequence Diagram

OO7 - Timing Diagram

  • Why there is no input processor: First of all, you need to know that the input order of my program is sauce:
  1. The console accepts IFTTT commands until RUN is entered, indicating the end of command input.
  2. According to the input instructions, start all the corresponding trigger threads, and let the main thread sleep for a short time in order to initialize all trigger threads and snapshots.
  3. Create and start a test thread to perform a series of file operations to test.
  4. After starting the test thread, the main program will wait for you to type END on the console to end all trigger threads that are not yet finished.
  • It can be seen that the input processor is not a separate thread, so I was lazy and wrote the input processing methods directly in the class method of Main.
  • In the above figure, in order to simplify, the parent class Monitor is used to replace the four types of monitor threads, because each type of monitor does similar things: continuously obtains new snapshots and compares them with the old ones to determine whether the trigger conditions are met and The corresponding action is performed, and whether the monitor's end condition is met. The properties of each type of monitor and the same part of what they do are extracted into the parent class Monitor.
  • There are a total of 4 types of monitor threads. Each monitor thread uses   the monitored object (a directory or a file) and  the trigger condition, that is, the monitor type (choose 1 from 4) as the monitor thread to distinguish it from other monitor threads. Flag, that is to say, there are at most 10*4 monitor threads in this program instead of 10*4*3.

 

Trigger conditions and monitoring conditions go through my readme as follows: (As the strategy mentioned in my last blog post , I went through all cases to avoid any conditions I missed)

Table 1

Table 2

Design class diagram

Refine it again, and there is a design class diagram: (I manually deleted and shifted)

 

 Program Metrics Analysis - Metrics

 

What is the cyclomatic complexity?

 

What is the depth of nested blocks? 

 

  • Well, it's still an old problem, and the functions are not subdivided and packaged.
  • And the run methods of my four types of monitors are relatively similar: I first wrote the most difficult RenamedMonitor, and then I found almost its bugs, and then copied it to the other three types of monitors, and performed part of the code. Modification, so as to avoid as much as possible after a bug is found, it will not rush to change the code of 4 or 2 sub-monitor classes.

 

  • [Share my coding experience this time]
  • First build a framework of a similar class, then write the Main method and input processing, and debug accordingly
  • Then finish writing the hardest RenamedMonitor
  • Then open a main method in RenamedMonitor, construct a RenamedMonitor object through parameters in this main method, and then call its  run( ) method  .
  • Start single-step debugging , and then directly operate the file system: create, move, rename, etc., file operations and single- step debugging  are interleaved, and you can also view the details or summary content of your real-time output.
  • The bug of the RenamedMonitor monitor is almost found. Similarly, the other three monitor classes can be debugged separately.
  • Finally, the single thread is almost adjusted, and multiple threads are started. At this time, it is not possible to test on the edge of multi-threading  as above .... Please print out the debug honestly. The problem that occurs at this time is basically the thread. Security and collaboration issues. It is still advisable that the previous steps have already debugged many small bugs for you.

thread safety considerations

  • When taking a snapshot, the file information will be read, and it is required that the file information cannot be changed at this time, so the method of the thread-safe file class SafeFile is set as a synchronization method.
  • In addition, if you only synchronize as described in the previous article, this may still happen: when traversing the files in a certain folder to take pictures, it is possible that when half of the pictures are taken, the CPU switches to the test thread, and the test thread File A has performed some operations. When the CPU switches back to continue taking pictures, the camera may have already taken pictures of file A. At this time, the message that file A has been changed will be delayed until the next snapshot is taken.
  • In order to solve this problem, I want to add a big lock. Before performing file operations or taking snapshots, this big lock must be obtained. This global lock is like this: Object lock = new Object( ).
  • (But thinking about it now, it seems that this delay is not a big problem. Anyway, the next photo QAQ will be taken soon....)

Self-Assessment of Strengths and Weaknesses and Reflection on Design Principles 

  • Advantages: The overall framework is relatively clear and logical; I have come up with a debug method to test on the edge of multi-threading; I have extracted the common methods and attributes of the four categories of monitors and put them in the parent class Monitor, the code reuse is not bad .
  • Disadvantages: (1) Some designs are unnecessary... (2) The functions are not divided and refined, and the readability and maintainability are not strong.
  • Reflect on the design principles: (1) The responsibilities of the method are not single and detailed enough, which violates the SRP principle and the principle of balanced distribution of responsibilities. (2) The DIP principle is not considered.

Bug Analysis

  • Debugging after class: When an object is copied, when is it necessary to copy the reference of the object, and when is it necessary to clone a new object, this problem repeatedly tormented me when I was debugging, so I quickly figured out the difference between the two. difference, and then start over again.
  • Beta: Safe.
  • Mutual testing - the other party: The design idea of ​​the other party is to open up to 120 monitor threads. Due to improper handling, the "If a file is monitored and there are more than one task to be executed after being triggered, if the file meets the If the trigger conditions are met, then sometimes these tasks will be executed, and sometimes these tasks will only be partially executed.” This is a problem that is easy to ignore when designing a framework. (I didn't think about this problem at the beginning. When I chose the idea of ​​opening up to 40 monitor threads, I was simply afraid that 120 threads would be too many....)
  • Mutual testing - our side: our side throws a NoPointerException, it seems because I later realized "if the monitored directory and the task after meeting the trigger condition includes recover, then whenever a file is monitored and meets the trigger condition, Just roll back the snapshot to the state before the file was changed" goal, which led me to fix one bug and then another bug surfaced....    
  • I serve.

 


 

Assignment 7 - Passenger Call and Answer System for Taxi

Design Framework - UML Sequence Diagram

OO7 - Timing Diagram

Total number of threads: main thread TaxiSys + input processing InputHandler + scheduler Scheduler + graphical interface GUI + taxi Car * 100 = 104 threads

  • Main thread: start other threads.
  • Input Processor: Constantly accepts console input, parses it, and if valid and non-homogeneous, puts the request into the request queue.
  • Scheduler: Constantly scan the request queue for requests. If the request window time does not come, it will search all taxis for the one that is eligible for order grabbing. If the request window time is up, delete the request from the queue, filter out the car that finally dispatches the order from all the cars that grab the order, and then tell the car, you go to respond to this request.
  • Taxi thread: Constantly check your own status and other information, and decide what to do next based on your own information.
  • GUI: Not much to say.

Design class diagram

With the design framework, it is further refined into a design class diagram: (I manually deleted it, in order to extract the key points and beauty)

To be more refined, my program includes these classes:

  • The black circles are the above 104 threads.
  • There are many attributes of taxis, and some of them do not need to be known by outsiders. In order to make it easier to transmit taxi information, I made a taxi information class. (Why did I not do RequestInfo, because the requested information is relatively simple... It is purely a personal idea, if you think this is not right, please leave a message for discussion)
  • For abstraction, I extracted the car's movement method into the CarMove interface. (Maybe there will be trucks, motorbikes...)
  • ErrorHandler you know.
  • FileLogger is a class for outputting logs. Considering the DIP principle and extensibility, I extracted it into the Logger interface.
  • The gui is provided by the course group. In order to read in the map file information and convert it into an array, I made MapInfo again.
  • The MyPoint class is made to extend the functionality of the Point class.
  • You also understand requests and request queues.
  • There are also some enumeration , which are not listed.

 Program Metrics Analysis - Metrics

 

A big improvement compared to the previous two.

Where is the cyclomatic complexity?

What is the depth of nested blocks? 

  • I can't help the gui class. I can't move my liver....
  • Both InputHandler and MapInfo are input processing, so I didn't consider splitting them. My input processing is relatively precise, I wrote 35 lines of code, and it seems to be split.
  • I split and packaged the Scheduler very well. What's going on? Found the scheduler's run method and I found this thing :)

thread safety considerations

  • The request queue is an object shared by the input processor thread and the scheduler thread, so I set all the methods of modifying or reading the content of the request queue to be synchronized methods.
  • Each taxi object is an object shared by the taxi thread and the scheduler thread, so I set the methods of modifying the taxi or reading information such as taxi status as synchronous methods.

Self-Assessment of Strengths and Weaknesses and Reflection on Design Principles

  • Advantages: The structure and logic are relatively clear, so debugging is more convenient.
  • Disadvantages: It does not feel very engineering; when looking for a taxi that can grab an order for a certain request, the method of traversing 100 taxis is used, which seems to be a waste of resources and time. Perhaps as the teacher said, [make several queues for taxis, and cars in different states enter different queues], which is more convenient to find, or [make several queues for taxis, and cars in different areas enter different queues]. Queue]?
  • Reflecting on design principles: Before this assignment, the teacher talked about design principles, so I implemented these design principles fairly well, but I feel good about myself.... I still have to look at the real engineering code [fighting]

Bug Analysis

  • Self-debugging after class: (1) I was hesitant about using wait(200) or Thread.sleep(200), and finally I thought about it like this: The methods of my taxi class are basically synchronous methods. The taxi itself and the dispatcher are the only people who may get the lock of the taxi. When the taxi spends 200ms in the movement process, it should give up the lock to the dispatcher, so use wait(200). Of course, if your thread synchronization design is different from mine, the conclusion may be different. (2) In order to be able to output log information in real time, and to avoid the problem of unsightly interleaving when all requests are output to a file in real time, I have allocated logs to different requests, but request 1 actually appeared during debug after class. Part of the log information of the request 2 is written in the log file of the request 2. I can't understand it. Later, I don't know why, but it's fine.... (Students who have encountered the same problem and know the mastermind behind the scenes are welcome to leave a message ...)
  • Beta: Passed
  • Mutual testing: We are safe, the output of the other party does not meet the requirements of the instruction book and the issue, and if there are more than 3 requests, an exception will be thrown, and there is a situation where a car matches 2 requests at the same time.
  • Peace at last.

 


 

Other summary

Changes in Design Strategy

  1. Changes in mentality: When I first came into contact with multithreading, as mentioned above, I was in a hurry and felt dizzy. Later, after mastering some routines, I was able to calm down and analyze, especially thread safety related issues. Of course, you need to have a sense of urgency while remaining calm. Anyway, I say to myself every now and then: You are going to be invalid, it’s invalid, laugh...
  2. Think from the big picture to the details. I usually think about and discuss the big frame first: how many threads should there be, what should each do, and what objects are there to share, and can this design meet those hard big requirements? Then think about how to adjust the widget to achieve those small requirements. Then I feel that it is almost the same, I will think about it and list a column. What are the classes, what are the properties and methods, are there things in common that can be extracted, and what thread safety issues need to be solved. Then start writing pseudocode on paper with as many design and implementation details as possible. Then start coding, in the process of coding, you may find some errors or omissions in your pseudo-code, which can be remedied at this time; in addition, every time I write a moderate-scale module that can be tested, I will first The module is debugged. Finally, debug the entire multithreaded program by printing.
  3. Try not to push down the refactoring (I don't have the ability and courage anyway). That's why I took the 2 strategies above.
  4. When coding code, try to consider the simplification and refinement of functions. Don't believe that you have time to extract some code segments into methods to normalize functions after debugging.

Strategies for finding bugs

The strategy described in my last blog post -

  1. Anatomy Instructions. I traversed the instruction book several times, and I simply listed out the regulations with a pen, and marked the relationship between different columns and easy-to-ignore points with a red pen. Then I did some in-depth thinking. For example, when the instruction book mentioned the possible states of a taxi, I drew a state machine. In-depth understanding of the instruction book is a prerequisite.
  2. Patches that have been applied to their own programs may also be easily missed by others.
  3. Different design methods will have different error-prone points. If the design method of the code you draw is different from yours, you can find other students who use this design method and ask them what bugs came out in class. For example, the "up to 40 thread design" and "up to 120 thread design" in the IFTTT job belong to two different design methods.
  4. Everyone's discussions in the discussion area and WeChat group are also listed one by one.
  5. Exchange test samples with your dear classmates. (If there are multiple threads, this basically doesn't work....)
  6. Looking at the problem from a more macro, complex, and traversal perspective makes it easier to spot the problem. For example, in the IFTTT job, I listed a table for analysis of whether different file operations meet the trigger conditions or end conditions of the four triggers.

On the basis of , some strategies are summarized:

  1. Self-test from simple to complex. It is easy to understand when self-testing, starting with small patches.
  2. When testing each other, you can be more flexible. You can blow it up with 100 inputs (like 100 taxi requests) to see if he's a boss, and if the result is different than expected, you can just smile (if the result is the same, you can also pray for it There are small bugs), and then test his code with test cases of separate function points, and then increase the complexity of test cases step by step. (Okay, I admit that when I blow it up, a big data is mainly to grasp the big picture....)
  3. Flexible construction of test cases. For example, in the taxi operation, I constructed such a fun example: send a request for a ride in every small area in the world, target Beihang, and then watch when most of the taxis on the GUI arrive at Beihang, the passengers It was found that all the Beihang people had taken the plane, so the passengers sent a lot of requests for rides near Beihang and wanted to leave, wherever they wanted. At this time, there will be many taxis grabbing the order, and then you can  judge which car should be finally allocated to the request according to the information of the car grabbing the order output in the log at the end of the request window . (Okay, this example is just for fun, maybe not very effective hehe....)
  4. I generally don't look closely at someone's code, unless that person's code is awesome and bug-free I'll start to appreciate it. But I will roughly combine the code design structure of the program under test to design test cases. Because different design structures will have different problems that are easy to miss.

        Thanks again for everyone who helped me~

I also continue to wish you all to learn OO and return on horseback~          

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325066912&siteId=291194637
7th
7th