CSC 145, First Ada Mult-tasking assignment 1. (Warmup.) Write a task A that repeatedly executes executes two consecutive statements: put("a"); put("a"); and a task B that repeatedly executes the two consecutive statements put("b"); put("b"); Make sure you use the task type and "access" declarations (see the sample program for details) for creating threads. Watch it run and become intrigued by the results. 1b. Add an entry start(x : integer) that will govern how many times a task will loop. 2. Study the Fibonacci server example (conc2.adb on webpage) You should have a function gcd and a procedure factorial from your first assignment (create others if you don't like these). You want to set up a server task for these functions. Let's start with just the gcd function. Define a task type gcdserver is entry request(x :integer; y:integer); entry getresult(x : out integer); end gcdserver -- you have to define the task body. Your task should work with the following kind of code: server1, server2 : gcdserver; x, y : integer; begin server1.request(4,6); server2.request(12,8); ... server1.getresult(x); server2.getresult(y); put(x); put(y); end ... That is, the computation of the gcd function should be done asynchronously. One axiom of concurrent programming is to maximize the use of concurrency. Do not put ANY code inside an accept ... do unless it really is necessary. That is, critical regions should be kept as small as possible. Your sever should also run in an infinite loop so it can handle multiple requests. To similate programs running longer, using busy while loops or delay(1.0); -- delays thread for approx. 1 second. Put a delay in your gcd function to similate it taking longer. 2b. Now you want your server to handle not only gcd requests but factorial requests. You'll need to modify your task so that there are two different request and two different getresult entries. You'll also need to use the "select" construct, so that a thread can call either entry. 2c. CLARIFICATION: THIS PROBLEM REQUIRES YOU TO CREATE TWO CLIENT TASKS. For example, you can create one task that always call requests and the another task that always call getresults. What if a client thread calls getresult before another calls request? Try it. If you're not careful, your server thread will be waiting for a request call while your client thread is waiting for the server to accept a getresult call. This situation is called a DEADLOCK! (congratulations). Each thread is waiting for the other. How do you get around This situation? Try putting all entries - requests as well as geresults, in one select construct. Then, add when conditions above the accepts. Use extra varibles to keep track of the internal state of the server. That is, a call to getresult should be ignored (without the server blocking) if the server has no result to serve. This final refinement requires you to use all the basic mechanisms - accept, select, and when all together. 3. Have you ever encountered the following kind of situation? You want to perform some operation such as download a very large file. A password is required to authorize the download. After you've typed in the password, you find to your mild surprise that a large portion of the download is already complete! It must have started downloading at the same time as you were typing in the password. We don't want nasty subversive elements to gain access to the gcd or the factorial service. Your request entries should ask for a password. But since most people in this world are honest, the chances are that the correct password will be entered. Therefore, you want to start the computation of gcd or factorial at the same time that the user is entering the password, so that no cpu cycles are wasted. You can accomplish this by starting another thread that checks for the password asynchronously. Furthermore, should the password entered be incorrect, you have to deny the request (but don't make any task hang forever). Here's sample code you can use to do string IO: S : String(1..16); -- declare string of up to 16 chars N : Integer; begin ... Put("enter password: "); Get_Line(S,N); -- read line from stdin -- S will contain string and N will contain number of chars in string. if ( S(1..5) = "xyzzy" ) then put("correct"); else put("incorrect"); end if; ... Use the "delay" command to implement a nice simulation. That is, show that the password checking is actually happening asynchronously.