Multiple active devices needed to cooperate with the CPU to provide services (e.g. read a disk block)
multiple active "sequential execution" streams, in the CPU and the controller
communications with I/O devices is inherently asyncronous
I/O controllers had varying response times and the CPU can not simply wait
If something has to happen event
To print the checksum
xxxxxxxxxx
151void computeChecksumAndPrint (char* buf, int blockNum, int numBytes) {
2 int xsum = 0;
3 for (int i = 0); i < numBytes; i++)
4 xsum ^= buf [i];
5 printf ("0x%1x\n", xsum);
6 free (buf);
7}
8
9void checksum (blockNum, numBytes, whenComplete) {
10 char* buf = malloc (numBytes);
11
12 diskRead (buf, blockNum, numBytes, whenComplete);
13}
14
15void checksum (1234, 4096, computeAndPrintChecksum)
Huge problem
An abstraction for execution
Creating and starting a htread
Stopping and re-starting a thread
Joining with a thead
xxxxxxxxxx
81void uthread_init (int num_processors);
2uthread_t uthread_create (void* (*proc)(void*), void* arg);
3void uthread_detach (uthread_t t);
4void uthread_join (uthread_t t, void **vp);
5uthread_t uthread_self ();
6void uthread_yield ();
7void uthread_block ();
8void uthread_unblock (uthread_t thread);
Explained
uthread_t
thread id data type
uthread_init
is called once to initialize the thread systemuthread_create
create and start a thread to run a specified procedureuthread_yield
temporarily stop current thread if other threads waitinguthread_join
join calling thread with specified other thread and get return valueuthread_detach
indicate thread no thread will join specified threaduthread_self
a pointer to the TCB of the current threaduthread_block
block current threaduthread_unblock
unblock specified thread and make it runnableGive up CPU if there's another thread that can run (i.e., pong())'
xxxxxxxxxx
81void* ping (void* v) {
2 int i;
3 for (i = 0; i < 100; i++) {
4 printf("I");
5 uthread_yield();
6 }
7 return 0;
8}
Give up CPU if there's another thread that can run (i.e., ping())
xxxxxxxxxx
81void* pong (void* v) {
2 int i;
3 for (i = 0; i < 100; i++) {
4 printf("O");
5 uthread_yield();
6 }
7 return 0;
8}
Give up CPU to wait for ping() to return and thus its thread to finish
xxxxxxxxxx
81void ping_pong () {
2 uthread_t t0, t1;
3 uthread_init(1);
4 t0 = uthread_create(ping, 0);
5 t1 = uthread_create(pong, 0);
6 uthread_join(t0, 0);
7 uthread_join(t1, 0);
8}
A program that reads a block from disk
xxxxxxxxxx
21read (buf, siz, blkNo); // read siz bytes at blkNo into buf
2nowHaveBlock (buf, siz); // now do something with the block
xxxxxxxxxx
21asyncRead (buf, siz, blkNo, nowHaveBlock);
2doSomethingElse ();
As a timeline
Create two threads that CPU runs, one at a time
Illusion of synchrony
xxxxxxxxxx
31asyncRead (buf, siz, blkNo);
2blockToWaitForInterrupt ();
3nowHowBlock (buf, siz);
xxxxxxxxxx
31interruptHandler() {
2 unblockWaitingThread();
3}
We wanted to do this, but couldn't because risk reads are asyncronous...
We implemented it this way in event-driven programming style...
Now we can do this...
We implemented it this way using threads to hide asynchrony...
The key new thing is blocking and unblocking
Thread State
Thread-Control Block (TCB)
Ready Queue
One or more Block Queues
Thread Scheduling is:
Thread Scheduling Policy
Things you might consider when setting scheduling policy
Priority
When choosing the next thread to run
Implementing Thread Mechanism
organize Ready Queue as a priority queue
priority queue: first-in-first-out among equal-priority threads
Preemption occurs when
Priority-based preemption
Quantum-based preemption
How long should quantum be?
The Problem
Timer Devices
Timer Interrupt Handler
Thread
Threads hide asyncrongy
Thread state
Round-robin, preemptive, priority thread scheduling