1. (a) sstf would be the best idea here. fcfs would suffer if the requests for the high demand cylinders were interspersed with requests for cylinders "far away". (b) sstf with a modification to prevent starvation. scan with an upper limit on the number of consecutive requests on the same track before moving on

You will obviously need to judge each of the answers.

2. Again, you will need to carefully judge each solution individually. Don't worry about the "language" they use to implement the algorithm. This is pure pseudocode. 

type diskhead=monitor

var busy: boolean
       up: condition
       headpos, count: integer

procedure entry acquire (dest:integer)

     begin
              if busy
                 then if headpos<= dest
                         then   up.wait(min{dest-headpos)
                         else   up.wait(min{dest})
                busy=true
                               
               headpos=dest
      end

procedure entry release
    
       begin
             busy=false
             up.signal
         end

       begin
              headpos=0
              count=0
        end
3. Threads are very inexpensive to create and destroy, and they use very little resources while they exit. They do use cpu time for instance, but they don't have totally separate memory spaces. Unfortunately, threads must "trust" each other to not damage shared data. For instance, one thread could destroy data that all the other threads rely on, while the same could not happen between processes unless they used a system feature to allow them to share data. Any program that may do more than one task at once could benefit from multitasking. 
For instance, a program that reads input, processes it, and outputs it could have three threads, one for each task. "Siingle minded processes would not  benefit from multile  threads-ffor instance, a program that displays the time of day.

4. User level threads have no kernel support, so they are very inexpensive to create, destroy and  switch among. However, if one  blocks. the whole process blocks. Kernel supported threads are more expensive because system calls are needed to create and destroy them and the kernel must schedule them. They are more powerful because they are independently scheduled and block individually. 

5. The system is easier to debug and modify because changes affect only limited sections of the system rather than touching all sections of the operating system. Information is kept only where it is needed and is accessible only within a defined and restricted area, so any bugs affecting that data must be limited to a specific layer. 

6. Processes which need  more frequent servicing, for  instance interactive processes such as editors, can be in a queue with a small time quantum. Processes with no need for ffrequet servicing can be in a queue with a larger quantum, requiring fewer context switches to complete the processing, making more efficient  use  of the machine. 

7. type resource=monitor

           var P: array[0..2] of boolean
                   X:condition 
          
           procedure acquire (id: integer, printer-id:integer)

                   begin
                        ii P[0] and P[1] and P[2] then X.wait(id)
                        if not P[0] then printer.id=0
                            else if no P[1] then printer.id=1
                                     else printer.id=2
                        P[printer.id]=true 
                    end

           procedure release (printer.id:integer)

                     begin
                       P[printer.id]=false
                        X.signal
                      end

           begin
               P[0]=P[1]=P[2]=false
           end