54 KiB
54 KiB
file:: ostep_1681115599584_0.pdf file-path:: ../assets/ostep_1681115599584_0.pdf
-
Part II
-
thread
ls-type:: annotation hl-page:: 311 hl-color:: yellow id:: 6433ca28-1bdf-433d-8ed9-0d54bf5ba940 collapsed:: true- share the same address space and thus can access the same data
- context switch: the address space remains the same hl-page:: 311 ls-type:: annotation id:: 6433cb70-d168-4863-8268-1e969df6ce06 hl-color:: yellow
- thread control blocks ls-type:: annotation hl-page:: 311 hl-color:: yellow id:: 6433cb56-fbef-46da-83c2-13fa2dba2967
- thread-local storage: one stack per thread in the address space hl-page:: 312 ls-type:: annotation id:: 6433cba2-61bd-4549-a29f-2ad85b3e30cd hl-color:: yellow
- Why thread?
collapsed:: true
- possible speedup through parallelization
- enable overlap of IO in a single program
- Though these could be done through multi-processing, threading makes share data easier
- KEY CONCURRENCY TERMS
ls-type:: annotation
hl-page:: 323
hl-color:: yellow
id:: 6433eabf-48d6-4776-b66f-a5f7804d1ddc
collapsed:: true
- indeterminate: the results depend on the timing execution of the code.
- race condition ls-type:: annotation hl-page:: 320 hl-color:: yellow id:: 6433e4cc-69e4-4057-8cc6-1766240d82f4
- A critical section is a piece of code that accesses a shared variable (or resource) and must not be concurrently executed by more than one thread. hl-page:: 320 ls-type:: annotation id:: 6433e52b-1f38-4f7c-b168-0aed624f9bdf hl-color:: yellow
- mutual exclusion: This property guarantees that if one thread is executing within the critical section, the others will be prevented from doing so. hl-page:: 320 ls-type:: annotation id:: 6433e566-e6ef-45b3-84b1-eba981be914a hl-color:: yellow
- Atomicity: as a unit, or, all or none hl-page:: 321 ls-type:: annotation id:: 6433e6a1-407c-4936-b184-dee868ef4107 hl-color:: yellow
- synchronization primitives ls-type:: annotation hl-page:: 322 hl-color:: yellow id:: 6433e729-7043-453b-8d60-6e6c41560543
- sane 精神健全的;神志正常的;明智的;理智的 ls-type:: annotation hl-page:: 322 hl-color:: green id:: 6433e6e7-d995-4b69-96b3-261b79f94c1d
- Thread API
hl-page:: 327
ls-type:: annotation
id:: 6433f35b-403b-4b25-b9f9-076e9e34777e
hl-color:: yellow
collapsed:: true
pthread_createpthread_joinpthread_mutex_lockpthread_cond_*
-
Locks
ls-type:: annotation hl-page:: 339 hl-color:: yellow id:: 6433f45b-0345-4790-8379-3d1a94e57ef5 collapsed:: true- A lock is just a variable
hl-page:: 339
ls-type:: annotation
id:: 6433f4ba-f2e4-4743-a536-e2b7747433b7
hl-color:: yellow
- lock variable: some type of variable, which holds the state of the lock(and maybe additional data such as its holder or a queue for acquisition)
- lock state: available (or unlocked or free); acquired (or locked or held)
- lock routines:
lock()tries to acquire the lock. If no other thread holds the lock, the thread will acquire the lock and enter the critical section(become the owner of the lock). Otherwise, it will not return while the lock is held by another thread.unlock(): The owner of the lock callsunlock(), then it is available again. If there are waiting threads, one of them will (eventually) notice (or be informed of) this change of the lock's state, acquire the lock, and enter the critical section.
- Locks help transform the chaos that is traditional OS scheduling into a more controlled activity hl-page:: 340 ls-type:: annotation id:: 6433f5e6-bc06-42a9-866e-e9a3053f528f hl-color:: yellow
- Controlling Interrupts
ls-type:: annotation
hl-page:: 342
hl-color:: yellow
id:: 6433fbfd-a1bf-4fd9-a54d-e15189c77b15
- For single-processor systems, disable interrupts for critical sections.
- Problems
- Disable interrupts is a privileged instruction. In the worst case, the OS may never regain control when the interrupt isn't going to be enabled.
- NOT work on multi-processor systems, each CPU has its own interrupt state
- importance interrupts may get lost
- inefficient
- Just Using Loads/Stores(Fail)
hl-page:: 343
ls-type:: annotation
id:: 6433fe7e-2221-41ee-ad6b-7deaa4459aa5
hl-color:: yellow
- use a simple variable (flag) to indicate whether some thread has possession of a lock
hl-page:: 343
ls-type:: annotation
id:: 6433ff4a-856d-4e4b-af30-6cb600aefeb5
hl-color:: yellow
- On acquisition, load, test the flag. If free, set the flag; If not free, spin-wait(loop load and test).
- On releasing, clear the flag.
- Problem
- When interrupted between load and test, mutual exclusion is broken.
- Low efficiency because of spin-waiting.
- use a simple variable (flag) to indicate whether some thread has possession of a lock
hl-page:: 343
ls-type:: annotation
id:: 6433ff4a-856d-4e4b-af30-6cb600aefeb5
hl-color:: yellow
- spin lock
- ((6436aafd-c85f-414c-8aee-acdc71e9138e))
- Requires a preemptive scheduler(or it may spin forever) and NO fairness guarantee
- For single processor systems, terrible performance, because the thread holding the lock cannot make any progress to release the lock until it is scheduled again and thus all other threads waiting for the lock can do nothing but spinning even they are scheduled.
- For multi-processor systems, spin lock may work well when thread B on CPU1 waits for thread A on CPU0, and the critical section is short. Because lock owner keeps making progress, spinning doesn't waste many cycles.
- Priority Inversion: Threads with high priority wait for locks held by threads with low priority. hl-page:: 355 ls-type:: annotation id:: 6435099b-0834-483e-9ef2-98a0b795cf00 hl-color:: yellow Solution: priority inheritance or give up the priority?
- Test-And-Set (Atomic Exchange)
hl-page:: 344
ls-type:: annotation
id:: 643401e0-fcec-41d3-9898-d5c4175ac464
hl-color:: yellow
- Returns the old value pointed to by the
old_ptr, and simultaneously updates said value tonew. - "test" the old value (which is what is returned) while simultaneously "set" the memory location to a new value
- ((6436af87-3f1b-4ee8-a2c8-4de0f1961f1a))
- Returns the old value pointed to by the
- Compare-And-Swap
hl-page:: 348
ls-type:: annotation
id:: 6434f8ac-d762-40a4-abb0-2955c2c8b396
hl-color:: yellow
- Test whether the value at the address specified by
ptris equal toexpected. hl-page:: 348 ls-type:: annotation id:: 6434fab0-08de-4f28-8d8e-f48f7e04aaaa hl-color:: yellow If so, update the memory location with thenewvalue. If not, do nothing. Return the old value at the memory location. - ((6436c5c7-32e7-4071-b909-4fdc14bb479d))
- ((b7679e9b-aabe-4bd3-8c2c-eb0a23fad491))
- Test whether the value at the address specified by
- load-linked and store-conditional
hl-page:: 349
ls-type:: annotation
id:: 6434fde1-9d19-4381-805e-f2a972875dc2
hl-color:: yellow
- The load-linked operates much like a typical load instruction, and simply fetches a value from memory and places it in a register. ls-type:: annotation hl-page:: 349 hl-color:: yellow id:: 6434fe1c-47f3-422c-a317-be72f08d6aef
- store-conditional only succeeds if no intervening store to the address has taken place.
hl-page:: 349
ls-type:: annotation
id:: 6434fe62-0e92-4414-86cc-b0c37fcf51ec
hl-color:: yellow
On success, return 1 and update the value at
ptrto value. On failure, return 0 and the value atptris not updated. - ((6436c620-4884-45a7-9273-b7952a6521ae))
- ((c38274a9-22dd-40e2-b74a-d3a9be63600e))
- Fetch-And-Add
ls-type:: annotation
hl-page:: 350
hl-color:: yellow
id:: 64350170-c853-4080-9ed1-2777ea3a18c8
- Atomically increments a value while returning the old value at a particular address
- ((6436c66c-807b-4e9d-93ed-b1d9703e6dc2))
- ticket lock
hl-page:: 351
ls-type:: annotation
id:: 64350331-8fbb-4c41-9ac1-1a4ba852f772
hl-color:: yellow
- ((6436af5c-0000-4bfb-9a27-1d7cf0a830db))
- Ensure progress for all threads. Once a thread is assigned its ticket value, it will be scheduled at some point in the future (i.e. it will definitely get its turn as
unlock()operations increase globalturnvalue). hl-page:: 351 ls-type:: annotation id:: 64350420-ca8a-4cac-af2f-f4e7deb5d1be hl-color:: yellow In contrast, test-and-set spin lock may starve, if it is very unlucky.(never succeeds in contention)
- Simple Yield Lock
hl-page:: 353
ls-type:: annotation
id:: 64350781-6995-41db-8b8e-2de0eb84136a
hl-color:: yellow
yield: a system call that moves the caller from the running state to the ready state, and thus promotes another thread to running. hl-page:: 353 ls-type:: annotation id:: 643507af-1153-46c1-b232-31a9a203e5df hl-color:: yellow- ((6436c684-ac4a-4144-9e7e-b4cb8f976c1f))
- Problem: Starvation is still possible; Context switch overhead, though better than spinning
- Lock With Queues, Test-and-set, Yield, And Wakeup
ls-type:: annotation
hl-page:: 354
hl-color:: yellow
id:: 64350b44-dfae-4544-93f9-ff2b343fefd4
- The real problem is: We have not much control over which thread to run next and thus causes potential waste. hl-page:: 353 ls-type:: annotation id:: 64350b4e-9559-49d9-aa37-eda9fe425b7f hl-color:: yellow
park(): put a calling thread to sleep hl-page:: 354 ls-type:: annotation id:: 64350bfb-64f7-4d41-8cc2-260dbec3372d hl-color:: yellowunpark(threadID): wake a particular thread hl-page:: 354 ls-type:: annotation id:: 64350c01-39bb-4d15-b554-0287b13806ee hl-color:: yellow- ((6436b05f-2873-4af4-952c-86d82685b583))
- When a thread is woken up, it will be as if it is returning from
park(). Thus whenunparka thread, pass the lock directly from the thread releasing the lock to the next thread acquiring it; flag is not set to 0 in-between. - wakeup/waiting race: If the thread is scheduled out just before it calls
park, and then the lock owner callsunparkon that thread, it would sleep forever. hl-page:: 356 ls-type:: annotation id:: 64351ba3-d4b5-4999-bc61-7733d5e0a061 hl-color:: yellow- One solution is to use
setpark(): indicate the thread is about topark. If it happens to be interrupted and another thread callsunparkbeforeparkis actually called, the subsequent park returns immediately instead of sleeping.
- One solution is to use
- Peterson's algorithm: mutual exclusion lock for 2 threads without hardware atomic instruction. Use 2 intention flags and a turn flag. hl-page:: 345 ls-type:: annotation id:: 6434edd3-2a7b-4e11-af18-29854e628bc6 hl-color:: yellow
- two-phase lock
hl-page:: 358
ls-type:: annotation
id:: 643522a7-4b16-4998-9b2f-47a852681a16
hl-color:: yellow
- A combination of spin lock and sleep lock
- In the first phase, the lock spins for a while, hoping that it can acquire the lock. hl-page:: 358 ls-type:: annotation id:: 6435230e-d84a-4c91-8329-b7608b0d543a hl-color:: yellow
- A second phase is entered if the lock is not acquired, where the caller is put to sleep, and only woken up when the lock becomes free later. ls-type:: annotation hl-page:: 358 hl-color:: yellow id:: 64352344-d140-468c-987c-e8afa05c2171
- Linux System Call futex
hl-page:: 356
ls-type:: annotation
id:: 64351e9a-6505-4176-a6fb-ddf63f3245a8
hl-color:: yellow
- each
futexis associated with ==a specific physical memory location==, and ==an in-kernel queue== futex_wake(address)wakes one thread that is waiting on the queue.futex_wait(address, expected)puts the calling thread to sleep, assuming the value ataddressis equal toexpected. If it is not equal, the call returns immediately.- Figure 28.10: Linux-based Futex Locks ls-type:: annotation hl-page:: 357 hl-color:: yellow id:: 64352221-d590-4371-a5f0-29e9cfa75ccb
- each
- A lock is just a variable
hl-page:: 339
ls-type:: annotation
id:: 6433f4ba-f2e4-4743-a536-e2b7747433b7
hl-color:: yellow
- efficacy 功效,效力 ls-type:: annotation hl-page:: 341 hl-color:: green id:: 6433fb69-1425-46b4-996f-f91da5d3e8d0
- foil ls-type:: annotation hl-page:: 347 hl-color:: green id:: 6434f523-44b7-40ab-8fea-528969c5acfd
- delve 钻研;探究;挖 ls-type:: annotation hl-page:: 349 hl-color:: green id:: 6434fb8c-2b3b-4d80-83fb-3b34da4dcd28
- brag 吹嘘;自吹自擂 ls-type:: annotation hl-page:: 351 hl-color:: green id:: 643501c1-f11b-4e85-8125-d2a5a31f69b0
- scourge 鞭打;鞭笞;折磨;使受苦难
-
Lock-based Concurrent Data Structures
ls-type:: annotation hl-page:: 361 hl-color:: yellow id:: 643525b0-e245-489b-877d-a2a1d63e7ea6 collapsed:: true- Concurrent Counters
hl-page:: 361
ls-type:: annotation
id:: 643525e5-fb85-48d4-905a-2a88b9ac0b0d
hl-color:: yellow
collapsed:: true
- Counter with lock
- Wrap the all the operations with a single lock.
- Performance is bad due to lock contention and it gets worse when the number of threads increases.
- perfect scaling: the increase in thread number doesn't harm the performance hl-page:: 363 ls-type:: annotation id:: 64352751-d9bd-4d5e-a8ba-cd18f86b1a15 hl-color:: yellow
- approximate counter
hl-page:: 363
ls-type:: annotation
id:: 64352794-d7c8-42f9-8321-f874967cebf2
hl-color:: yellow
- represent a single logical counter via ==numerous local physical counters==(one per CPU core), as well as ==a single global counter==. Each actual counter has a ==lock==.
- To add the counter, acquire the ==local lock== and increase it, thus avoiding contention.
- To read the counter, acquire the ==global lock== and read.
- To keep the global counter up to date, the local values are periodically transferred to the global counter and reset, which requires ==global lock and local lock==. A threshold
Sdetermines how often this transfer happens, tuning the trade-off between scalability and precision.
- Counter with lock
- Concurrent Linked Lists
ls-type:: annotation
hl-page:: 367
hl-color:: yellow
id:: 643530d8-9d09-4c8a-9e92-47dfe814ef50
collapsed:: true
- Again, the simplest way to implement this is to wrap all operations on the list with a single lock.
- Assuming the
mallocis ==thread-safe==, we can improve the code a little by narrowing critical section: only operations on global structure need to be locked. - hand-over-hand locking: a lock per node.
hl-page:: 369
ls-type:: annotation
id:: 64353237-4b74-4148-b7c1-5854d83a18c7
hl-color:: yellow
- When traversing the list, the code first grabs the next node's lock and then releases the current node's lock.
- In practice, it ==doesn't work== due to prohibitive overhead
- Concurrent Queues
ls-type:: annotation
hl-page:: 370
hl-color:: yellow
id:: 64353353-9de2-421b-967d-dc80a597eecd
collapsed:: true
- Two locks, head and tail, for
enqueueanddequeueoperation. - Add a dummy node to separate head and tail operation. Without this,
dequeueoperation needs to acquire both locks in case the queue is empty.
- Two locks, head and tail, for
- Concurrent Hash Table
hl-page:: 372
ls-type:: annotation
id:: 6435360d-c176-494a-9d61-b1fd0107a9bd
hl-color:: yellow
collapsed:: true
- instead of having a single lock for the entire structure, it uses a lock per hash bucket ls-type:: annotation hl-page:: 372 hl-color:: yellow id:: 6435363d-c697-42a6-bfd0-8a2332cef394
- Concurrent Counters
hl-page:: 361
ls-type:: annotation
id:: 643525e5-fb85-48d4-905a-2a88b9ac0b0d
hl-color:: yellow
collapsed:: true
- ubiquitous 似乎无所不在的;十分普遍的 ls-type:: annotation hl-page:: 372 hl-color:: green id:: 6435365a-b5d6-46fc-a9a1-25b0d23aa529
- humble 谦逊;低声下气;虚心;贬低 ls-type:: annotation hl-page:: 373 hl-color:: green id:: 6435367f-dd9e-449d-b0e4-3d8c9e14f6c2
- sloppy 马虎的,草率的;(衣服)宽松肥大的;太稀的,不够稠的; hl-page:: 376 ls-type:: annotation id:: 643536c8-fc05-4bbe-8d1d-0f4f6d1c4fee hl-color:: green
- gross 总的,毛的;严重的,极端的;粗鲁的;臃肿的;粗略的; hl-page:: 378 ls-type:: annotation id:: 643537d3-7d01-442b-b47e-59433c2aa6db hl-color:: green
-
condition variable
hl-page:: 378 ls-type:: annotation id:: 643537ff-1028-4725-8d7a-c0338cc946d3 hl-color:: yellow collapsed:: true- A ==condition variable== is an explicit queue that threads can put themselves on when some state of execution(condition) is not as desired (by waiting on the condition); some other thread, when it changes said state, can then wake one (or more) of those waiting threads and thus allow them to continue (by signaling). hl-page:: 378 ls-type:: annotation id:: 64353882-7697-4c16-8e53-c8f59ea256c1 hl-color:: yellow
- Operations
wait()put the caller to sleep.pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)hl-page:: 378 ls-type:: annotation id:: 643538d5-9ea3-4399-9fa2-d75fdf0e1dd4 hl-color:: yellowsignal()wake up a sleeping thread waiting on this condition.pthread_cond_signal(pthread_cond_t *c);hl-page:: 379 ls-type:: annotation id:: 643538de-cc40-4dd2-8f03-9492004f209b hl-color:: yellow- The
wait()also takes a mutex as a parameter; it assumes that this mutex is locked whenwait()is called. The responsibility ofwait()is to ==release the lock and put the calling thread to sleep== (atomically); when the thread wakes up, it must ==re-acquire the lock before returning== to the caller. The design is helpful to avoid some race conditions when trying to sleep. - use a while loop instead of just an if statement when deciding whether to wait on the condition. ls-type:: annotation hl-page:: 380 hl-color:: yellow id:: 643547c5-1613-49e9-899e-0e86f59a1462
- stem (花草的)茎;(花或叶的)梗,柄;阻止;封堵;遏止;
hl-page:: 379
ls-type:: annotation
id:: 64353eb8-8ed8-4680-a3c0-91608b429408
hl-color:: green
- **stem from sth ** 是…的结果;起源于;根源是
- Producer/Consumer Problem
hl-page:: 382
ls-type:: annotation
id:: 64354974-adea-4b20-90f4-a12ebe1e4d5b
hl-color:: yellow
collapsed:: true
- Mesa semantics: Signaling a thread only wakes them up; it is thus a hint that the state of the world has ==changed==, but there is ==no guarantee== that when the woken thread runs, the state will ==still be as desired==. (Another guy may run before the thread and change the state again)
hl-page:: 385
ls-type:: annotation
id:: 64354cc4-14c5-408d-b879-7d4d011b2b5c
hl-color:: yellow
- So, always use while loops. While loops make sure the thread wake up in the desired state of world, which tackles the ((64355502-f41f-40dd-b71f-e0abdbc76716)) and provides support for ((64355441-5a1b-4015-baa1-65917526079c)) hl-page:: 386 ls-type:: annotation id:: 64354db0-8c74-4c14-b063-d26378a10555 hl-color:: yellow
- Hoare semantics: provides a stronger guarantee that the woken thread will run immediately upon being woken hl-page:: 386 ls-type:: annotation id:: 64354d46-4286-44fd-9e82-2ba562a50f25 hl-color:: yellow
- Incorrect Solution: single condition variable. The problem arises from the ==undirected wakeup operation==: God knows which thread is to be woken up.
- Envision multiple consumers and one producer:
- producer
P1increases count to 1, signals the CV and sleeps - consumer
C1is awaken, reduces count to 0, signals the CV and sleeps - another consumer
C2is woken up ==by accident==, finds out count is 0, sleeps - In this case, they all sleep and thus nobody will signal any of them
- producer
- If in step 3, the producer
P1is woken up, everything is fine. Obviously, one solution is to ==exert control over which thread is to be woken up==. Well, wake up all threads may also solve this problem, see ((64355441-5a1b-4015-baa1-65917526079c)).
- Envision multiple consumers and one producer:
- Correct solution: 2 condition variable.
- Producer threads wait on the condition
empty, and signalsfill. Conversely, consumer threads wait onfilland signalempty. - ((6436b07d-9279-46bb-9c6b-985eb2324df8))
- Producer threads wait on the condition
- spurious wakeups
hl-page:: 390
ls-type:: annotation
id:: 64355502-f41f-40dd-b71f-e0abdbc76716
hl-color:: yellow
- In some thread packages, due to details of the implementation, it is possible that two threads get woken up though just a single signal has taken place.
- covering condition
hl-page:: 391
ls-type:: annotation
id:: 64355441-5a1b-4015-baa1-65917526079c
hl-color:: yellow
- covers all the cases where a thread needs to wake up, other threads simply wake up, re-check condition and go back to sleep
pthread_cond_broadcast()wakes up all waiting threads
- Mesa semantics: Signaling a thread only wakes them up; it is thus a hint that the state of the world has ==changed==, but there is ==no guarantee== that when the woken thread runs, the state will ==still be as desired==. (Another guy may run before the thread and change the state again)
hl-page:: 385
ls-type:: annotation
id:: 64354cc4-14c5-408d-b879-7d4d011b2b5c
hl-color:: yellow
- albeit 尽管;虽然 ls-type:: annotation hl-page:: 390 hl-color:: green id:: 64354f54-b26c-48dc-a328-4ae355b680f3
- spurious 虚假的;伪造的;建立在错误的观念(或思想方法)之上的;谬误的 hl-page:: 390 ls-type:: annotation id:: 643554f4-75a7-48fa-9366-87058ee723fb hl-color:: green
-
Semaphores
hl-page:: 396 ls-type:: annotation id:: 64356d96-cce8-48ad-80f1-e3e02a1a4684 hl-color:: yellow collapsed:: true- A semaphore is an ==object with an integer value== that we can manipulate with two routines
sem_wait()andsem_post(). The initial value determines its behavior, so we need to give it an initial value throughsem_init()hl-page:: 396 ls-type:: annotation id:: 64356dba-48b4-49b8-8182-c962f12f03a5 hl-color:: yellow - Semaphore: Definitions Of Wait And Post
ls-type:: annotation
hl-page:: 397
hl-color:: yellow
id:: 6435744b-a300-40ad-ba91-157666d8cd2a
sem_wait(sem_t *s): First decrement the value of the semaphore by one. Then wait if the value of semaphore is negativesem_post(sem_t*s): First increment the value of the semaphore by one. If there is any thread waiting, wait up one of them- The value of the semaphore, when negative, is equal to the ==number of waiting threads== hl-page:: 397 ls-type:: annotation id:: 64357512-e25b-4226-961a-caec367fc8a3 hl-color:: yellow
- Binary Semaphores (Locks)
ls-type:: annotation
hl-page:: 398
hl-color:: yellow
id:: 6435753a-65b5-4e46-82bc-54c11c1cd533
- Initialize semaphore to 1, indicating we only have one piece of resource (the critical section).
- Wrap the critical section with
sem_waitandsem_post - When the lock is acquired, the semaphore is 0. On another acquisition request, the value goes to -1, which makes the caller sleep. When the lock is free, the value is decreased to 0 on acquisition, which will not get stuck.
- Semaphores For Ordering (Condition Variable, or Ordering Primitive)
hl-page:: 399
ls-type:: annotation
id:: 64357930-2d96-4867-bc3d-2fe89990ce5f
hl-color:: yellow
- Initialize the semaphore to 0
- Consider the join operation. The parent calls
sem_waitand the child callssem_post. In either case, no matter which thread is scheduled first, the semaphore guarantees the desired result.
- The Producer/Consumer (Bounded Buffer) Problem (Again)
hl-page:: 401
ls-type:: annotation
id:: 64357c6d-381e-492e-b901-095454f5315e
hl-color:: yellow
- 2 semaphores
emptyandfullfor coordination between consumer and producer, and 1 semaphore for lock - Initialize
empty <- MAX, andfull <- 0 - Consumer waits for
fulland postsemptyand conversely, produce waits foremptyand postsfull - Special case for
MAX=1- When only one slot is available in the buffer, we don't even need a lock! Actually, it is binary semaphore which not only controls the buffer entry but also works as a lock.
- Otherwise, there will be a ==data race== inside the
put/getoperation due to potential multi-thread access to these procedures (whenMAX > 1, thesem_wait(&empty)may allow in more than one thread).
- Deadlock avoidance
- If the lock semaphore is the outmost semaphore, deadlock occurs (the thread may sleep in
sem_wait(&empty)withmutexunrelease). Therefore, put the lock inside theempty/fullsemaphore pair.
- If the lock semaphore is the outmost semaphore, deadlock occurs (the thread may sleep in
- ((6436bebd-0681-4f94-9d04-4d8e4a554512))
- 2 semaphores
- Readers-Writer Locks
ls-type:: annotation
hl-page:: 406
hl-color:: yellow
id:: 643583b4-26b1-4cbf-801c-11ed6e63976e
- Either allow ==multiple readers to read== concurrently, or allow ==only one writer to write==.
- Two sets of operation
rwlock_acquire/release_writelock(): simplywait/postthewritelockrwlock_acquire/release_readlock(): acquirewritelockwhen the ==first reader acquires==, and release it when the ==last reader releases==
- ((6436c668-5be8-4ce1-b701-1f2a00d34cc9))
- Problem: More overhead; Unfairness, writer is much more likely to starve.
- To tackle the writer starvation problem, we may manually wake up the writers (if ever suspended) every time read lock releases. Wiki
- The Dining Philosophers
hl-page:: 408
ls-type:: annotation
id:: 643587a7-ade4-4f09-be50-aea233ff02c0
hl-color:: yellow
- Background setting
hl-page:: 408
ls-type:: annotation
id:: 6435889f-1375-4b94-8630-b3d0d7bdfa56
hl-color:: yellow
- 5 "philosophers" around a table. Between each pair of philosophers is a single fork (and thus, 5 total). The philosophers each have times where they think (don’t need forks), and times where they eat. In order to eat, a philosopher needs two forks (left and right). The contention for these forks is our synchronization problem.
- Solution
- A semaphore per fork, and helper function
left/right(p)which is the fork on philosopherp's left/right. - Deadlock: if each philosopher tries to grab the fork on their left first, there will be a deadlock. When all of them get their left-side forks, all of the forks are locked and no one could get their right-side fork.
- Non-deadlock: force one philosopher to try to grab the right-side fork first
- ((6436bebd-0681-4f94-9d04-4d8e4a554512))
- A semaphore per fork, and helper function
- Background setting
hl-page:: 408
ls-type:: annotation
id:: 6435889f-1375-4b94-8630-b3d0d7bdfa56
hl-color:: yellow
- Implement Semaphores
ls-type:: annotation
hl-page:: 411
hl-color:: yellow
id:: 643589a6-31e6-4603-9259-999e9c8860f7
- Implementing Zemaphores With One Lock And One CV: the book authors provide us a simple implement for semaphore. hl-page:: 412 ls-type:: annotation id:: 64358de1-f418-44fd-8a77-bc0faa368059 hl-color:: yellow
- ((6436c47e-dc86-4452-b9b5-4e7997dbfbfb))
- A semaphore is an ==object with an integer value== that we can manipulate with two routines
- salient 最重要的;显着的;突出的: ls-type:: annotation hl-page:: 397 hl-color:: green id:: 64357404-d348-42b3-96a3-ba28575baa66
- ensue 跟着发生,接着发生; ls-type:: annotation hl-page:: 408 hl-color:: green id:: 64358802-3b22-46ed-a0e2-71cc9df69a7b
- Throttle 节流阀;风门;喉咙;使窒息;使节流; hl-page:: 411 ls-type:: annotation id:: 64358758-cb9c-4e8d-aaa4-f8e50457db88 hl-color:: green
- bog 沼泽;泥塘;使陷于泥沼;使动弹不得 hl-page:: 411 ls-type:: annotation id:: 64358755-1fae-4ea2-93a3-8c9d3d3e11c3 hl-color:: green
- ramification (众多复杂而又难以预料的)结果,后果 hl-page:: 410 ls-type:: annotation id:: 64358b0c-e441-4d0a-852d-ecfde369306c hl-color:: green
- Non-Deadlock Bugs: A large fraction (97%) of non-deadlock bugs studied by Lu et al. are either ==atomicity violations== or ==order violations==. hl-page:: 420 ls-type:: annotation id:: 64361e4c-62eb-4599-9809-0f77f9ce1cd0 hl-color:: yellow
-
Deadlock
hl-page:: 420 ls-type:: annotation id:: 64361fb7-5aa6-45cd-8b1e-aa0d0c300ad2 hl-color:: yellow collapsed:: true- Conditions for Deadlock
hl-page:: 422
ls-type:: annotation
id:: 64361fd1-49ff-4023-8493-840ac423086a
hl-color:: yellow
- If any of these four conditions are not met, deadlock cannot occur.
- Mutual exclusion: Threads claim exclusive control of resources that they require
- Hold-and-wait: Threads hold resources allocated to them while waiting for additional resources
- No preemption: Resources cannot be forcibly removed from threads that are holding them.
- Circular wait: There exists a circular chain of threads such that each thread holds one or more resources that are being requested by the next thread in the chain.
- Prevention: break the conditions for deadlock
hl-page:: 422
ls-type:: annotation
id:: 643620d9-cdb6-4073-89f4-f9f8ac223073
hl-color:: yellow
- Circular Wait: Never induce a circular wait.
hl-page:: 422
ls-type:: annotation
id:: 643620fb-edc6-43b2-b4b2-43b010cfc46e
hl-color:: yellow
- total ordering and partial ordering of lock acquisition (think about your Discrete Math, total ordering is a restricted form of partial ordering, in partial ordering, some pairs of elements are not comparable)
- Anyways, follow some kind of ordering when acquire lock in order to avoid cycles.
- ENFORCE LOCK ORDERING BY LOCK ADDRESS ls-type:: annotation hl-page:: 423 hl-color:: yellow id:: 64362497-58cd-45da-8ab5-84f96e899e16
- Hold-and-wait: acquiring all locks at once, atomically.
hl-page:: 423
ls-type:: annotation
id:: 643625fe-423c-4b18-8c22-32d38720c5d0
hl-color:: yellow
- Not practical
- No Preemption
hl-page:: 424
ls-type:: annotation
id:: 64362632-50e8-41dd-a1bc-bbf3d4312b0f
hl-color:: yellow
trylockeither grabs the lock (if it is available) and returns success or returns an error code indicating the lock is held- Instead of blocking at the lock call, give up all previous locks and try over again if some of the locks is not available.
-
while (true) { mutex_lock(&lock1); if (mutex_trylock(&lock2) == 0) break; else mutex_unlock(&lock1); } - livelock problem: in some special cases, two threads may keep trying and giving up locks due to each other's intervention
hl-page:: 424
ls-type:: annotation
id:: 6436281f-4fdc-4586-83fb-b686cec3b76b
hl-color:: yellow
- random delay before looping back and trying the entire thing over again
- Mutual Exclusion: lock-free data structures
hl-page:: 425
ls-type:: annotation
id:: 643629ba-e746-41a6-b073-1199b3db3691
hl-color:: yellow
- use atomic instructions provided by hardware
- Circular Wait: Never induce a circular wait.
hl-page:: 422
ls-type:: annotation
id:: 643620fb-edc6-43b2-b4b2-43b010cfc46e
hl-color:: yellow
- Avoidance
hl-page:: 427
ls-type:: annotation
id:: 64362af4-9b35-4e27-8ba2-0f5f8817526a
hl-color:: yellow
- By careful scheduling, deadlock could be avoided.
- Limited usage: OS does not always have sufficient knowledge to make deadlock-free scheduling. Such approaches also limit concurrency.
- Banker's Algorithm
- Detect and Recover
ls-type:: annotation
hl-page:: 428
hl-color:: yellow
id:: 64362c62-3a12-4bcb-95ae-baf1ca69312e
- Allow deadlocks to occasionally occur, and then take some action once such a deadlock has been detected.
- Conditions for Deadlock
hl-page:: 422
ls-type:: annotation
id:: 64361fd1-49ff-4023-8493-840ac423086a
hl-color:: yellow
- terrific 极好的;绝妙的;了不起的;很大的 ls-type:: annotation hl-page:: 428 hl-color:: green id:: 64362b38-6dfb-4c00-8aa6-b756e8983de4
- maxim 格言;箴言;座右铭 ls-type:: annotation hl-page:: 428 hl-color:: green id:: 64362b40-5f07-418f-83f3-c83eb5927c94
- nasty 极差的;令人厌恶的;令人不悦的;不友好的 ls-type:: annotation hl-page:: 432 hl-color:: green id:: 64364569-01b4-45e1-83f8-ac1bd8af5850
-
Event-based Concurrency
hl-page:: 432 ls-type:: annotation id:: 64364585-ace4-4920-87fe-87aad004dffd hl-color:: yellow collapsed:: true- event loop: waits for something to do and then, for each event returned, processes them, one at a time
hl-page:: 433
ls-type:: annotation
id:: 643658f3-4761-4d0c-b044-4cadcfea27aa
hl-color:: yellow
- event handler ls-type:: annotation hl-page:: 433 hl-color:: yellow id:: 643658f9-5eee-4d1a-a3d6-4f8eb9ed3d7b
selectorpollhl-page:: 433 ls-type:: annotation id:: 64365db8-a249-46bc-bd9c-237251c544b5 hl-color:: yellow- Check whether there is any incoming I/O that should be attended to.
-
int select( int nfds, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict errorfds, struct timeval *restrict timeout); - Examine if some of their descriptors are ready for reading/writing or have an exceptional condition pending. The first n descriptors are checked in each set hl-page:: 434 ls-type:: annotation id:: 64365eb6-5310-4893-9d11-5e332ef84c4a hl-color:: yellow
selectplaces the given descriptor sets with ==subsets of ready descriptors==.select()==returns the total number of ready descriptors== in all the sets. hl-page:: 434 ls-type:: annotation id:: 64365ef8-3c62-4d78-8bc6-d0a4b2c81d49 hl-color:: yellow
- Block IO: NO blocking calls are allowed in event-based systems, because it will just stop the whole process.
- Asynchronous I/O
ls-type:: annotation
hl-page:: 437
hl-color:: yellow
id:: 643693db-d363-46ee-b0d6-910b30408946
- Issue an I/O request and return control immediately to the caller, before completion. Additional interfaces to determine whether the IOs have completed. hl-page:: 437 ls-type:: annotation id:: 64369701-8a39-4aa4-9985-129572c04f53 hl-color:: yellow
- AIO control block
aiocb int aio_read(struct aiocb *aiocbp);issues an asynchronous read requestint aio_error(const struct aiocb *aiocbp);checks whether the request (designated by theaiocb) has completed- Checking IO completion is inefficient, perhaps we need interrupt-based approaches (e.g. UNIX signals) to inform applications when async IO completes.
- Problems
- State management
- manual stack management: when an event handler issues an asynchronous I/O, it must package up some ==program state for the next event handler== to use when the I/O finally completes; this additional work is ==not needed in thread-based programs==, as the state the program needs is on the stack of the thread. hl-page:: 438 ls-type:: annotation id:: 6436a3d9-ee29-4378-af79-4efc770cc209 hl-color:: yellow
- continuation: record the needed information to finish processing this event in some data structure; when the event happens (i.e., when the disk I/O completes), look up the needed information and process the event. hl-page:: 440 ls-type:: annotation id:: 6436a40a-121f-4fab-b428-b278e4cb65d3 hl-color:: yellow
- Utilizing multiple CPUs hl-page:: 440 ls-type:: annotation id:: 6436a46c-f845-4c7b-8bb1-97da71589c67 hl-color:: yellow
- Implicit blocking such as paging hl-page:: 440 ls-type:: annotation id:: 6436a485-7a70-4974-93d2-9e11b010a948 hl-color:: yellow
- Messy code base due to complicated asynchronous logic
- State management
- event loop: waits for something to do and then, for each event returned, processes them, one at a time
hl-page:: 433
ls-type:: annotation
id:: 643658f3-4761-4d0c-b044-4cadcfea27aa
hl-color:: yellow
- obstinate 固执的;棘手的;难以去除的; hl-page:: 448 ls-type:: annotation id:: 6436ca1f-f4e7-431e-9620-be7764825acd hl-color:: green
- pickle 泡菜;腌菜 ls-type:: annotation hl-page:: 448 hl-color:: green id:: 6436caa1-6fe0-4de8-9ad4-2a057960fc1a
-
System Architecture
ls-type:: annotation hl-page:: 450 hl-color:: yellow id:: 6436cc2e-b1af-4555-9d1d-808e6de120b1 collapsed:: true- memory bus, general IO bus, peripheral bus
- Canonical Device
hl-page:: 452
ls-type:: annotation
id:: 643786f0-5f9c-4441-8898-82ccd6a1a464
hl-color:: yellow
- Hardware interface with protocols which allows OS software to control and internal structure which implements the abstraction
- Canonical Protocol
hl-page:: 453
ls-type:: annotation
id:: 64378926-ce8a-4e38-a3fe-62fb5c4994e6
hl-color:: yellow
- Interface is comprised of 3 registers: status, command, data.
-
- Poll the device, i.e. repeatedly read the status register to see if the device is ready
- Transfer some data to data register
- Write a command to the command register, informing the device to work
- Poll again to see if it is completed
- programmed I/O (PIO): CPU is involved with the data movement hl-page:: 453 ls-type:: annotation id:: 64378c55-677c-4ab7-94c6-02ff41b90ded hl-color:: yellow
- Interrupt instead of poll
- Polling wastes CPU time, then interrupts come up. The OS ==issues a request, put the caller to sleep, and context switch==. When the device is done, it raises a hardware interrupt, causing CPU jump to the ==interrupt service routine==(ISR), which ==finishes the request and wakes up the process==.
- Interrupt is no panacea.
- Not suitable for ==high speed devices== which may complete the work on first poll. Interrupt only adds to the overhead
- Not suitable for network due to possible livelock: with ==huge amount of packets incoming==, the systems may find itself ==only processing interrupts== and never allowing a user process to service these requests.
- Interrupt coalescing: raise a single interrupt for multiple tasks. hl-page:: 455 ls-type:: annotation id:: 64378e9e-0f95-4312-a19e-3ee9d0b4ef1e hl-color:: yellow
- Direct Memory Access (DMA)
hl-page:: 456
ls-type:: annotation
id:: 64379241-c097-4aaa-b545-582df132b35f
hl-color:: yellow
- Programmed IO also wastes CPU: it does nothing but tediously copying data.
- To transfer data to device, OS tells DMA controller the data address and size and then context switch. Then DMA does the rest copying work which overlaps with CPU.
- IO instructions and memory-mapped IO
- Device Driver
hl-page:: 457
ls-type:: annotation
id:: 6437989d-c18e-4cc7-9cb0-737384cc7960
hl-color:: yellow
- Encapsulates any ==specifics of device== interaction. ==Software in OS== which knows detail of device at the ==lowest level==.
- Figure 36.4: The Linux File System Stack
ls-type:: annotation
hl-page:: 458
hl-color:: yellow
id:: 643799a7-dfae-46e0-88e6-ebf587755d75
- System Call API, File System/Raw, Generic Block Interface(block r/w), Generic Block Layer, Specific Block Interface (protocol r/w), Device Driver
- A Simple IDE Disk Driver
ls-type:: annotation
hl-page:: 458
hl-color:: yellow
id:: 64379e9a-840a-48c9-b804-03e6b179a6a6
- An introduction to the xv6 IDE driver, which gives an intuition about how the stuff works, quite trivial.
- manifold ls-type:: annotation hl-page:: 450 hl-color:: green id:: 64378274-897c-4aac-b246-49bda634b872
- oblivious ls-type:: annotation hl-page:: 457 hl-color:: green id:: 64379a07-5bc3-49b2-93e2-f371ad2b5347
- haul ls-type:: annotation hl-page:: 460 hl-color:: green id:: 64379b8b-7c37-4d7e-8135-1d025eb42ae3
- trailer ls-type:: annotation hl-page:: 460 hl-color:: green id:: 64379b93-cb30-45a8-afe6-53052c08fa6f
- obscure ls-type:: annotation hl-page:: 460 hl-color:: green id:: 64379ba3-e41d-411f-ab6d-9a5f1424ac26
-
Hard Disk Drives
ls-type:: annotation hl-page:: 464 hl-color:: yellow id:: 64379f7c-b440-4023-bc10-fd27071ec742 collapsed:: true- Address Space of HDD: Array of sectors (512-byte block), numbered from 0 to n-1, which can be read/written as a unit. hl-page:: 464 ls-type:: annotation id:: 6437a316-6185-4eae-bc56-eeca9c5dfc0d hl-color:: yellow
- Only a ==single sector write is atomic==, though multi-sector operations are possible (e.g. widely-used 4KB r/w)
- one can usually assume that accessing two blocks near one-another within the drive’s address space will be faster than accessing two blocks that are far apart. One can also usually assume that accessing blocks in a contiguous chunk (i.e., a sequential read or write) is the fastest access mode, and usually much faster than any more random access pattern. ls-type:: annotation hl-page:: 465 hl-color:: yellow id:: 6437a4a9-3103-4830-abc7-dba0b1067b76
- Components of Disk
hl-page:: 465
ls-type:: annotation
id:: 6437a4da-bca4-4f13-b018-30f3400d169f
hl-color:: yellow
collapsed:: true
- platter (大平盘): a circular hard surface on which data is stored, an HDD is comprised of one or more platters hl-page:: 465 ls-type:: annotation id:: 6437a4f2-5d89-495a-a984-b427a3d03e74 hl-color:: yellow
- surface: 2 sides of a platter hl-page:: 465 ls-type:: annotation id:: 6437a4f9-3de4-451b-a7cc-faf67b8530e8 hl-color:: yellow
- spindle (轴;纺锤): connected with a motor that spins the platters bound around it. rotations per minute (RPM) hl-page:: 465 ls-type:: annotation id:: 6437a4fd-450b-49ff-acd1-e46d3b507079 hl-color:: yellow
- track: a concentric circle of sectors, a surface consists of many tracks. hl-page:: 465 ls-type:: annotation id:: 6437a503-6b91-4b61-b288-9cea9c2ea832 hl-color:: yellow
- disk head: magnetic sensor, one per surface hl-page:: 465 ls-type:: annotation id:: 6437a50b-a53a-476b-8ef2-8bcbc21d7073 hl-color:: yellow
- disk arm: all disk heads connect to the disk arm, which moves disk head to get to the desired track hl-page:: 465 ls-type:: annotation id:: 6437a50f-5c6c-47ff-9179-ac48118342d7 hl-color:: yellow
- IO time
collapsed:: true
- Rotational Delay: wait for the desired sector to rotate under the disk head hl-page:: 466 ls-type:: annotation id:: 6437a841-9b37-42dc-a8dc-339085099a5a hl-color:: yellow
- Seek operation: move the disk head to the ==desired track==.
hl-page:: 467
ls-type:: annotation
id:: 6437aa03-61a9-40c1-ba53-98d0e1ab87b9
hl-color:: yellow
- Seek phases: Acceleration (start), Coasting (move at full speed), Deceleration (slow down), Settling (stop carefully, often take most of the time)
- General IO process: 1. seek; 2. waiting for the rotational delay; 3. finally the transfer. hl-page:: 467 ls-type:: annotation id:: 6437abff-a6b8-4d28-8a4e-8e67fe9cdd4d hl-color:: yellow
- Mathematical Analysis
ls-type:: annotation
hl-page:: 469
hl-color:: yellow
id:: 6437bbc8-c313-4ec2-81ef-c3b0969214e4
- IO time:
T_{IO} = T_{seek} + T_{rotation} + T_{transfer} - IO rate:
R_{IO} = \frac{Size_{\text{trans}}}{T_{IO}} - random workload, issues small (e.g., 4KB) reads to random locations on the disk hl-page:: 470 ls-type:: annotation id:: 6437d014-ef82-45e4-8083-974da0d39296 hl-color:: yellow
- sequential workload, reads a large number of sectors consecutively from the disk ls-type:: annotation hl-page:: 470 hl-color:: yellow id:: 6437d023-d891-45f1-89e5-c08801e33d71
- As for random workload,
T_{\text{trans}} \approx \frac{Size_{\text{trans}}}{\text{Peak Transfer Rate}},T_{\text{rotation}} \approx \frac{1}{2}\frac{1}{\text{RPM}/60}andT_{seek}is an average value measured by manufacturer. id:: 6437bb98-57d2-4924-af5c-74b6be542e8f - As for sequential workload, we can assume there is ==a single seek and rotation== before ==a long transfer==, and the result is very close to the Peak Transfer Rate, especially when read size is very large.
- Average Seek Time is roughly 1/3 of a full seek (from inner-most track to out-most), which could be derived from a simple integral hl-page:: 472 ls-type:: annotation id:: 6437d17a-0bee-478e-a843-fea71d3b74e2 hl-color:: yellow
- IO time:
- Miscellaneous details about HDD
- Track skew: optimization for continuous read across track boundary hl-page:: 467 ls-type:: annotation id:: 6437acc8-bc95-466b-9d04-acfe22b0eeee hl-color:: yellow
- Multi-zoned Disk: outer tracks tend to have more sectors than inner tracks. a zone is a set of tracks with the same number of sectors, and a disk is organized into multiple zones hl-page:: 468 ls-type:: annotation id:: 6437ad1b-5292-4a42-80c4-8a1ff9f7f691 hl-color:: yellow
- cache, write back and write through hl-page:: 468 ls-type:: annotation id:: 6437ada7-4a51-4032-bdcc-110b47796be9 hl-color:: yellow
- Disk Scheduling
hl-page:: 473
ls-type:: annotation
id:: 6437d1c9-ffce-44b6-b9ee-9e8c4d29a3fc
hl-color:: yellow
- FCFS
- Though not included in this textbook, put it here for a full covering.
- SSTF: Shortest Seek Time First
ls-type:: annotation
hl-page:: 473
hl-color:: yellow
id:: 6437d47e-ea32-439d-98c2-364af2d48f58
- First complete requests on the ==track nearest== to the disk head's current track. hl-page:: 473 ls-type:: annotation id:: 6437d48d-ce5b-4a23-b2b3-00d1696a54b5 hl-color:: yellow
- Nearest Block First (NBF): schedule by block address, because the track information is unavailable for OS (OS only sees an array of blocks).
- Problem: ==starvation== of requests to far-away tracks
- Figure 37.8: SSTF: Sometimes Not Good Enough
ls-type:: annotation
hl-page:: 475
hl-color:: yellow
id:: 6437e177-28f4-4b48-a501-f8e0620b3026
- When
T_{seek} \gg T_{rotation}, SSTF is a good policy - When
T_{seek} \lt T_{rotation}, sometimes it is better to seek to another track than to wait for a full rotational time.
- When
- Elevator (SCAN)
hl-page:: 474
ls-type:: annotation
id:: 6437d990-abcf-4f2d-a9c1-13f7c853c00a
hl-color:: yellow
- Move back and forth across the disk servicing requests in order across the tracks. If a request for a block on a track already serviced in this sweep (a single pass from outer to inner tracks, or reversed), it won't be handled until next sweep. hl-page:: 474 ls-type:: annotation id:: 6437da6a-2921-4909-a9b9-b5cbd844e04b hl-color:: yellow
- F-SCAN: freeze the queue during a sweep, which avoids starvation of far-away requests, though delays late-arriving (but nearer by) requests.
- C-SCAN: sweep in a single direction (and than reset) rather than both. A bit more fair for outer and inner tracks, because bi-directional sweep favors middle tracks (twice).
- Problem: it doesn't make any effort to emulate SJF. Instead, it ==only prevents starvation==.
- SPTF: Shortest Positioning Time First
ls-type:: annotation
hl-page:: 475
hl-color:: yellow
id:: 6437e26b-14ef-49f3-968a-956509d62296
- SSTF is not the best policy for modern HDDs where seek time and rotation time are roughly equal.
- SPTF requires detailed information about the disk internals. Thus, it becomes a part of the disk controller rather than driver in OS. OS issues a few requests to disk controller, and the disk itself decides how to serve these requests.
- FCFS
- in/at a pinch 必要时;不得已时 hl-page:: 475 ls-type:: annotation id:: 6437e0d2-c585-4c74-a7d1-500ae29b38df hl-color:: green
- gem 宝石 hl-page:: 475 ls-type:: annotation id:: 6437e0db-ceb2-4b13-ae37-5598fa7dd519 hl-color:: green
-
Redundant Arrays of Inexpensive Disks(RAIDs)
hl-page:: 480 ls-type:: annotation id:: 6437e8b0-b179-46c1-9173-e9b080273f7e hl-color:: yellow collapsed:: true- RAID Interface
- Look like a ==big, fast and reliable disk==, which provides an abstraction of ==a linear array of blocks==. Usually, a RAID is connected to the host through ==standard interfaces== (e.g. SATA)
- Internally, the RAID controller decides how to perform ==physical I/Os== in order to complete a single ==logical I/O==.
- At a high level, a RAID is very much a specialized computer system: it has a processor, memory, and disks; however, instead of running applications, it runs specialized software designed to operate the RAID. ls-type:: annotation hl-page:: 482 hl-color:: yellow id:: 6437ef13-e1d1-4dce-bbd9-1a6f09dae4f0
- Fault Model
ls-type:: annotation
hl-page:: 482
hl-color:: yellow
id:: 6437ef79-0ca3-4937-9861-2648b2579524
- fail-stop fault model
- A disk can be either working or failed. If working, all blocks can be read/written. If failed, permanently lost (ignore realistic errors like corruption or latent sector error).
- Disk failure can be immediately detected
- fail-stop fault model
- RAID0: Striping
hl-page:: 483
ls-type:: annotation
id:: 6437f261-2d97-4f0c-85aa-06dd6d230ce0
hl-color:: yellow
- spread the blocks of the array across the disks in a round-robin fashion ls-type:: annotation hl-page:: 483 hl-color:: yellow id:: 6437fe8e-f81a-4646-aab2-87c5b3376e91
- Chunk Size: number of consecutive blocks placed in one disk before moving on to the next disk
hl-page:: 484
ls-type:: annotation
id:: 6437feab-eceb-4f11-9ced-ae43e2798c0c
hl-color:: yellow
- Small chunk size increases parallelism but positioning time increases as well
- Large chunk size decreases parallelism but positioning time also decreases (more consecutive reads in the same disk)
- Capacity: Full utilization,
Ndisk each of sizeBblocks makeN*Bblocks available - Reliability: No redundancy at all.
- Performance: Full utilization in parallel. Single-request latency is identical to that of a single disk, while it offers full bandwidth as for steady-state sequential throughput.
- Two performance metrics
- single-request latency: how much parallelism can exist during a single logical I/O operation
- steady-state throughput: total bandwidth of many concurrent requests, under two basic types of workload: ==random and sequential==
- RAID1: Mirroring
hl-page:: 486
ls-type:: annotation
id:: 64380351-ec20-460c-bf79-a423d22e59e3
hl-color:: yellow
- make more than one copy of each block in the system
- Read: read from any one of these copies; Write: update all copies
- ((64382b19-3f45-4fb0-9160-638bdbfdf481))
- Capacity: expensive, only half of RAID0
- Reliability: RAID1 can tolerate at least 1 disk failure, and up to
N/2failures depending on the actual situation - Performance
- Single-request latency:
-
- As for read, identical to a single disk.
- As for write, slightly higher than a single disk because it has to wait for multiple disks.
-
- Steady-state throughput:
-
- Under sequential workload, only half the total bandwidth.
- Random write also gets half of the bandwidth.
- However for random read, full bandwidth is available by distributing reads across redundant disks (We can't do this for sequential read, in comparison to RAID0, because the operation needs to skip blocks while it is a consecutive read in RAID0, see ((64380cd0-34b3-4c34-8c35-a5cf1bf77eee))).
-
- To see that this is not the case hl-page:: 489 ls-type:: annotation id:: 64380cd0-34b3-4c34-8c35-a5cf1bf77eee hl-color:: yellow
- Single-request latency:
- make more than one copy of each block in the system
- RAID4: Parity
hl-page:: 489
ls-type:: annotation
id:: 64380d3f-30a1-4780-aff2-96cfeb474786
hl-color:: yellow
- Add an additional disk to store the parity information for other disks.
- Each block in the parity disk stores the XOR of other disks' blocks which are in the same stripe.
- XOR indicates if there are odd or even number of 1s in the input. Given the parity bit and the remaining bits, any one bit lost can be recovered. With this parity bit, we just count how many 1s are there in the remaining bits and the lost bit can be derived. id:: 6438114c-fb40-4e2f-a60a-59f48922f5db
- Parity computation (single write)
id:: 64382061-9676-4d98-af30-d033789eed50
- additive parity: read all other data blocks in the same stripe in parallel, do XOR, and write the new data block and new parity block in parallel hl-page:: 491 ls-type:: annotation id:: 643821ec-6db3-410c-87bf-0a2c9928cdf9 hl-color:: yellow
- subtractive parity: read the old data block and the old parity block, if new bit is identical to the old bit, parity stays unchanged; else, parity bit flips, and finally write them in parallel (Because we are dealing with blocks, there is little chance that the parity block stays totally unchanged).
ls-type:: annotation
hl-page:: 491
hl-color:: yellow
id:: 64382387-01fb-4f28-b5bf-d68dcb529642
The calculation can be expressed as
P_{new} = (C_{old} \oplus C_{new}) \oplus P_{old}
- Capacity:
(N-1)*Buseful capacity - Reliability: tolerate 1 disk failure and only 1
- Performance:
- Single-request latency
id:: 643811af-3534-4f5c-bc93-ae6da9056d5d
-
- Single read is identical to a single disk
- Single write is roughly twice of a single disk (2 reads and 2 writes, both in parallel).
-
- Steady-state throughput
-
- Sequential read can use all disks except the parity disk, i.e.
(N-1)*S. - Sequential write is also
(N-1)*Sin average. The blocks are consecutive and in large quantity, so we can perform full-stripe write, i.e. calculate parity and write the whole stripe (including the parity disk) in parallel, without overhead. - Random read is similar to sequential read,
(N-1)*R - Random write is only half of a single disk,
R/2. small-write problem: even though data disk writes can be done concurrently, the parity disk force them to serialize. In either way ((64382061-9676-4d98-af30-d033789eed50)), parity disk requires 1 read and 1 write, thus halving the bandwidth.
- Sequential read can use all disks except the parity disk, i.e.
-
- Single-request latency
id:: 643811af-3534-4f5c-bc93-ae6da9056d5d
- RAID5: Rotating Parity
hl-page:: 493
ls-type:: annotation
id:: 6438241b-f487-4cf3-b717-60811340a5bd
hl-color:: yellow
- Improved version of RAID4, RAID5 rotate the parity block across drives.
- ((64382b1e-7c59-4729-a70f-68005b0640b4))
- Performance
- Except for Random R/W, all other stuff is almost identical to RAID4
- Random read: slightly larger bandwidth, since we can use all disks now,
N*R - Random write: allow for some parallelism, but conflict still exists (data block and parity block on the same disk), so there can be ==at most N/2 operations at the same time==.
N/4 * R = N/2 * (R/2)
- Figure 38.8: RAID Capacity, Reliability, and Performance ls-type:: annotation hl-page:: 494 hl-color:: yellow id:: 64382a3d-6747-462d-8431-7775ad76cc22
- RAID Interface
- latent 潜在的;潜伏的;隐藏的 ls-type:: annotation hl-page:: 482 hl-color:: green id:: 6437f025-9841-4e02-a629-66940e341341
- incur 招致,引发;蒙受 hl-page:: 484 ls-type:: annotation id:: 6437fffc-d2d1-4dbc-a28e-89e95b6efdfa hl-color:: green
- deem 认为,视作;相信 hl-page:: 485 ls-type:: annotation id:: 64380150-55a0-493e-9fee-a5c666a095d4 hl-color:: green
- taxonomy 分类学,分类系统 ls-type:: annotation hl-page:: 495 hl-color:: green id:: 64382546-3a1e-438d-9f0e-434018661bda
- tandem 串联,串联的 hl-page:: 498 ls-type:: annotation id:: 64382ab8-ad41-4c20-be74-3ce7446f20d6 hl-color:: green