Your computer is built so that when the power
is turned on, it loads a certain address into the program counter and starts
running. That address is a program in ROM that is very short and simple.
Typically, it reads in a certain fixed chunk of the disk. This piece of
the disk typically holds a larger program that reads in the rest of the
The set off all processes in a machine at anytime is kept in the process table. This table holds the process state, priority, owner, etc. The process can be ready meaning it can run as soon as a timeslice becomes available. It can be blocked which means it is waiting for some external event like user input. It can also be running. The scheduler examines this table and determines what runs next. There are a lot of scheduling algorithms.
When a process is started (or restarted) the dispatcher sets a timer for the time slice. At the end of the quantum, an interrupt goes off that causes the CPU to record where it is in the current process and handle the interrupt. The program that it calls at this point is called the interrupt handler. When this interrupt goes off, the scheduler wakes up, evaluates the process table based on priority and ready state, and selects the next process to run. There is an interesting symbiosis between modern processors and OSes. The processors have been built with special hardware to enable process switching in support of multi-tasking OSes. This kind of mutual development has been going on for a long time. New software is developed to allow new capabilities and hardware is modified to support them. A recent example is the MMX extensions to Intel processors. Instructions were added to speed up some kinds of graphics processing that had been done in software before.
If a process starts to do I/O, it may stop before its time slice is up. In this case, it is marked blocked and a new process is started. The first processes may start again when the I/O is completed and its state is changed to ready.
Processes are allowed to communicate using inter-process
communication. There are a variety of ways to do this including shared
memory and networking protocols. An overall structure to this is provided
using the client-server model. This term is usually used to describe
a problem solution where part of the answer is on the users desk (client)
and part on the main machine (server). This can also apply to processes
within one machine. One process is the client. It uses information provided
by the server. An example is a database system. There is a server process
that actually retrieves data from the disk storage and there are multiple
client processes that ask for that data. Building system using this architecture
simplifies construction. Each component is the same whether it is being
run on the same computer as the client or not. It also allows specialization
and efficiency in server design which can lead to improved performance.
In the computer, a semaphore is a flag. In general, a flag is
a piece of memory that records the on/off state of something. In a loop,
you might set a flag to tell the loop when to stop. If it starts out being
true, the loop continues until you set it false. Then the loop exits.
A flag can be represented as a single bit, but is usually larger.
A semaphore is a flag used to tell if some resource is available. When a process wants to use a protected resource, it first checks the semaphore. If the semaphore is clear, the process sets it so that another process can't use the resource.
The difficult part of this comes from the machine language for checking and setting a memory location. The way the semaphore works is to fetch the value from memory, compare it to 1. If it is 0, then set it to one. In our machine, this would be something like.
|1||2001||LOAD 1 into R0|
|2||1120||LOAD mem(20) into R1 (semaphore value)|
|3||B130||JUMP mem(30) if R1 == R0 (semaphore is already 1)|
|4||3020||SET mem(20) to 1 (set semaphore)|
Remember that processes run for a quantum and then are interrupted. These interrupts can happen between any two instructions. So process A could complete instructions 1 and 2 and then get interrupted. Process B completes all 4 instructions and gets interrupted. If the initial value of the semaphore is 0, Process B now thinks it owns the semaphore and has set it to 1. Process A now starts up again and continues at instruction 3. Since it previously loaded a 0 into R1, it goes to instruction 4 and sets the semaphore to 1. Process A now thinks it owns the resource and goes ahead and uses it. When it gets swapped out, Process B starts again and also uses the resources.
To prevent this, processors have an instruction called 'test and set'. This checks if a memory location has a 1 in it and if not, sets it to 1. This is done as one instruction so the interrupt problem described above doesn't happen.
When the process is done with the resource, it must set the semaphore back to 0. Does this have the same interrupt problem as the check above?
The section of the program that is protected by a semaphore is called a critical region. Semaphores can be more elaborate. They could have a value greater than 1 and count backward. This kind doesn't let any process in unless the value is 0. This is used if there are as small number of the resource available. An example is a system with several tape drives.
Having multiple copies of a resource raises another similar problem. If Process A needs two tape drives and gets one before it gets swapped out and Process B also needs 2 tape drives and locks up one. If there are only two drives, neither one can run because each needs a resource that the other has. This is called deadlock. Another example is when the system process table is full and some processes need to create processes in order to finish.
The solutions for this problem are varied. One approach is to do nothing. When a deadlock occurs, we detect it and take some action to correct the problem. In the tape drive case, we could kill one of the processes and then the other can complete. We could also require that all process request all resources at once, so we can't have partially fulfilled requests. Another technique is to make it appear to the processes that the resource has more copies. This is often done with printers. Instead of writing directly to the printer, a process writes to a file, thinking it is a printer. Later, the OS sends the contents of the file to the printer. This way, no process has to wait for the printer to physically finish printing before it can start. This is called spooling after the analogy of wrapping the print jobs onto a spool and unspooling them to the printer later. This also makes use of the concept of queues.