分类: 服务器与存储
2012-03-26 09:07:56
每个进程多数情况下并不能完整地用完所得到的时间片(因为中断,比如I/O)而不得不放弃对CPU的使用权,所以线程(Thread)的概念由此诞生。当 进程中的某个线程等待I/O操作时,另外的线程可以继续运行,直到用完所得到的时间片。对进程来说,CPU的资源就像钱对人类一样珍贵。
随着硬件技术的发展,多核和多处理器技术可以让线程真正地并发运行。
线程共享进程中的内存空间以及资源,但拥有独立的栈。线程的实质是保存在寄存器中的一些状态——程序指针(IP)和栈指针(SP)。当线程切换时,发生改 变的仅仅是这两个存放在寄存器中的指针值,被激活的线程便根据新的IP值开始执行程序,并始用当前SP所指的栈,所以线程切换是非常迅速的。相对而言,进 程的切换非常慢,因为进程的切换要切换虚拟内存空间,导致页表切换。
线程在内存中只有栈是私有的,有时它需要在栈外维护一个私有存储空间(Thread Local Storage, TLS),比如全局变量。Windows下可以调用TlsAlloc来获得这块存储区域。相关的函数分别是:TlsAlloc反回一个 index,TlsGetValue(index)返回这个存储区里的值,TlsSetValue(index, value)设置存储的值,TlsFree(index)释放这个存储区(注:这个函数会释放会令这个index在所有线程中失效,所以要确保最后退出进 程的线程调用该函数)。另一种在栈外存储私有数据的方式是私有堆(Private Heap),相关的Windows函数HeapCreate, HeapAlloca, HeapFree和HeapDestory。
线程同步
Mutex:当线程获得Mutex时,其它尝试得到这个Mutex的线程都会被挂起,直到持有这个Mutex的线程释放该Mutex;
Semaphore: Mutex的进化版,通过计数允许多个线程获得这个资源,而不像Mutex一次只能被一个线程获得。当获取Semaphore的线程数达到最大值时,则尝试获取Semaphore的线程就会挂起,直到有线程释放Semaphore。
Event: 当某个Event发生时,唤醒等待该事件的线程。有两种方式:Sychronization和Notification。前者只唤醒最先等待该事件的线程,后者唤醒所有待待该事件的线程。
Waitable Timer: 相当于Time Event,当计时器时间到后,就会唤醒线程。
Critical Section: 类似于Mutex,当一个线程进入临界区(enter critical section)后,其它尝试进入的线程都会被挂起,直到该线程离开临界(leave critical section)区。与Mutex不同,进入临界区的线程再次进入临界区(在递归函数里会出现这种情况),而Lock Mutex的线程再试尝试Lock同一个Mutex,会造成死锁(Dead Lock)。
Slim Reader/Writer: 当某个线程尝试读操作,如果有别的线程正在进行写操作,则挂起;否则即使有别的线程正在进行读操作。当线程尝试写操作,只要有别的线程在进行读操作或写操作,则挂起。
Condition Variables: 这个Variable必须与Mutex或Critical Section一起使用。当一个线程获得了一个Mutex或进入了临界区,当它block住(比如等待I/O)时,可以放弃这个Mutex或离开临界区, 同时挂起;当block这个线程的原因消失后(比如I/O操作完成),并且Mutex或临界区没有被其它线程占用,它可以重新获得这个Mutex或临界 区。
同步造成的问题
Starvation:某一线程可能无法得到Mutex而始终无法运行。比如Priority太低Mutex总是被更高优先级的线程占据。
Dead lock:当两个线程同时占有对方想要的Mutex时,会导致死锁。比如一个线程得到了A,等待B,而另一线程得到了B,等待A,这时两个线程因为得不到想要的Mutex,而无法运行下去。
Live lock:解决Dead lock可以有一个timeout的方法。当一个线程等待一个Mutex超时后,释放掉自己占有的Mutex。这种方案可能会出现这种情况:线程获得A, 等待B超时后释放A;而另一个线程获得B,等待A超时释放B。之后两个线程又同时获得了对方想要的Mutex,等待超时后又再次释放已获得的Mutex。 如此反复。
Interlocked Operations
有些原子操作是可以在用户模式(User Mode)下完成的,从而省去了进入操作系统内核的开销,更高效:
Interlocked[In|De]crement(&a) <==> a++ 或 a--
InterlockedAdd(&a, b) <==> a += b
InterlockedExchanged(&a, b) <==> a = b
Interlocked[xor|and|or](&a, b) <==> a ^= b 或 a &= b 或 a |= b