Vocabulary
context switch: 上下文切换
OS scheduler: 操作系统调度程序
concurrent :happening or existing at the same time 并发的,同时发生的;并存的
mutual exclusion: 互斥锁
synchronization primitive:
1. requires some synchronization primitives: 需要一些同步原语
2. Threads as synchronization primitives: 线程的同步单元
Comparison between threads and processes
Apparently
private virtual memory for each process
Perhaps another way to think of this is that each thread is very much like a separate process, except for one difference: they share the same address space and thus can access the same data.
More details
The **context switch** between threads is quite similar to the context switch between processes, as the register state of T1 must be saved and the register state of T2 restored
before running T2. With processes, we saved state to a process control block (PCB); now, we’ll need one or more thread control blocks (TCBs) to store the state of each thread of a process.
There is one major difference, though, in the context switch we perform between threads as compared to processes: the address space remains the same.
One other major difference between threads and processes concerns the stack.
Why use Threads?
The first is simple: parallelism**.**
The task of transforming your standard single-threaded program into a program that does this sort of work on multiple CPUs is called parallelization, and using a thread per CPU to do this work is a natural and typical way to make programs run faster on modern hardware.
The second reason is a bit more subtle: to avoid blocking program progress due to slow I/O.
Threading enables overlap of I/O with other activities within a single program, much like multiprogramming did for processes across programs
Notice:
Of course, in either of the cases mentioned above, you could use multiple processes instead of threads. However, threads share an address space and thus make it easy to share data, and hence are a natural choice when constructing these types of programs. Processes are a more sound choice for logically separate tasks where little sharing of data structures in memory is needed.
An Example: Thread Creation—线程是如何被创造和运行的
The main program creates two threads, each of which will run the function mythread()
.
After creating the two threads (let’s call them T1 and T2), the main thread calls pthread_join()
, which waits for a particular thread to complete.
It does so twice, thus ensuring T1 and T2 will run and complete before finally allowing the main thread to run again; when it does, it will print “main: end” and exit. Overall, three threads were employed during this run: the main thread, T1, and T2.
Note: The scheduler decided to run Thread 2 first even though Thread 1 was created earlier;
there is no reason to assume that a thread that is created first will run first.
Why Multithreading Gets Worse: Shared Data →The Heart Of The Problem: Uncontrolled Scheduling
`mov 0x8049a1c, %eax
add $0x1, %eax
mov %eax, 0x8049a1c`
process:Thread1 ran and finished(初始时counter是50,结束之后counter+1) → a timer interrupt goes off; thus, the OS saves the state of the currently running thread (its PC, its registers including eax
, etc
.) to the thread’s TCB→ Thread2 runs(由于没有执行mov %eax, 0x8049a1c
counter是50,结束之后counter=51) → Thread1 runs again(Recall that it had just executed the mov
and add
, and is now about to perform the final mov
instruction. 所以counter依旧为51)→ the counter shows 51 “correctly”
It is called data race. Because multiple threads executing this code can result in a race condition, we call this code a critical section. A critical section is a piece of code that accesses a shared variable (or more generally, a shared resource) and must not be concurrently executed by more than one thread.
What we really want for this code is what we call mutual exclusion. This property guarantees that if one thread is executing within the critical section, the others will be prevented from doing so.
Atomic operations
build a general set of what we call synchronization primitives
从jyy的课整点笔记来吧QWQ做个标记
mentions about the condition variable
A kind of mechanism which gives support this type of **sleeping/waking **interaction that is
common in multi-threaded programs