Journal 27
July 23 - July 29
This week's workload wasn't too bad thanks to the midterm, but all the time that would have been spent on a programming assignment was spent on studying for the exam, so it wasn't quite a freebie week. I am always bewildered by how fast these 8 weeks go by; I cannot believe this marks the end of week 5. This week's reading was quite interesting, and held a lot of information that was completely new to me.
Chapter 26 served as an introduction to concurrency. Threads allow for multiple executions within a process as each thread has its own program counter, registers, and stack. All threads share the same address space despite these individual components. Multi-threading has a big impact on performance improvement. Parallelism uses multiple processors for computation, thus increasing performance capabilities. Similarly, the use of multiple threads allows for overlap of I/O and computation within a program. In code, pthread_create() and pthread_join() is used for thread creation. Concurrency establishes non-determinism within programs as thread execution orders vary widely. While threads can improve performance, it can also create shared data issues such as race conditions when two threads increment a shared counter.
Chapter 27 delves further into the use of pthread_create() and pthread_join(). Create starts threads while join waits for thread completion. It is stressed that we do not return stack-allocated memory in order to safely handle memory. Mutex locks such as pthread_mutex_lock() and pthread_mutex_unlock() protect critical sections, while PTHREAD_MUTEX_INITIALIZER and pthread_mutex_init() handle initialization. This chapter also provided some example wrappers for error handling should we run into issues.
Chapter 28 explored the concept of locks further. A lock makes sure only one thread executes a critical section at a time, referred to as mutual exclusion. When coding, lock() and unlock() allow for an exclusive portion in which to execute critical selection. Spin locks repeatedly check if a lock is available through a while loop:
(while (lock->flag == 1);)
and are described as efficient on multi-CPU systems, but can be wasteful on single-core systems. Atomic hardware primitives such as test-and-set and compare-and-swap implement spin locks. When evaluating performance of locks, metrics such as correctness, fairness, and performance are often used.
Chapter 29 takes a look at lock-based concurrent data structures. Locks can be applied to make data structures thread-safe, such as the use of pthread_mutex_t as a thread-safe counter. A single global lock can limit scalability and performance, though. Approximate counters are local counters per CPU with occasional aggregation to a global count. Thus, approximate counters achieve high performance but come with the caveat that they may have slight inaccuracies. In an example, a linked list with locks can have minimized locking by only locking during pointer updates rather than malloc().
Comments
Post a Comment