进程是一个具备必定独立功能的程序在一个数据集上的一次动态执行的过程,是操做系统进行资源分配和调度的一个独立单位,是应用程序运行的载体。
进程通常由程序,数据集合,进程控制块三部分组成。
程序用于描述进程要完成的功能,是控制进程执行的指令集;
数据集合是程序在执行时所须要的数据和工做区;
程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的惟一标志。程序员
线程(Thread),有时被称为轻量级进程(LightweightProcess,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。一般意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间及一些进程级的资源。编程
内核线程(Kernel Thread, KLT)就是直接由操做系统内核支持的线程,这种线程由内核来完成线程切换,内核经过操做调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。通常一个处理核心对应一个内核线程。
用户线程就是咱们一般意义上所讲的轻量级进程线程。
用户线程与内核线程的对应关系有三种模型:安全
在如今流行的操做系统中,大都采用多对多的模型。多线程
在单处理器对应多线程的状况下,并发是一种模拟出来的状态。操做系统会让这些多线程程序轮流执行,每次仅执行一小段时间(一般是几十到几百个毫秒),这样每一个线程就“看起来”在同时执行。这样的一个不断在处理器上切换不一样的线程的行为为线程调度。
线程调度中,线程一般有三个状态:并发
处于运行中的线程拥有一段能够执行的时间,这段时间称为时间片(Time Slice)。
当时间片用尽时,该线程进去就绪状态。
若是在时间片用尽以前线程就开始等待某件事。那么它会进入等待状态。
当一个线程离开运行状态时,调度系统就会选择一个其余的就绪线程继续执行。
在一个处于等待状态的线程所等待的时间发生以后,该线程进入就绪状态。函数
优先级调度决定了线程按照什么顺序轮流执行,在具备优先级调度的系统中,线程拥有各自的线程优先级(Thread Priority)。具备高优先级的线程会更早地执行,而低优先级的线程一般要等没有更高优先级的可执行线程时才会被执行。
线程的优先级能够由用户手动设置,此外系统也会根据不一样情形调整优先级。
在线程调度机制下存在线程饿死现象。一个线程饿死是说它的优先级较低,在它执行以前老是有比它优先级更高的线程等待执行,所以这个低优先级的线程始终得不到执行。为了不线程饿死,调度系统一般会逐步提高那些等待了好久而得不到执行的线程的优先级。这样,一个线程只要等待了足够长的时间,其优先级总会被提高到可让它执行的程度,也就是说这种状况下线程终会获得执行,只是时间的问题。
在优先级调度环境下,线程优先级的改变有三种方式:性能
多线程程序处于一个多变的环境当中,可访问的全局变量和堆数据随时均可以被其余的线程改变。所以多线程程序在并发时数据的一致性很是重要。
为了不多个线程同时读写同一个数据而产生预料不到的后果,咱们将各个线程堆同一个数据的访问同步(Synchronization) 。所谓同步(synchronization)就是指一个线程访问数据时,其它线程不得对同一个数据进行访问,即同一时刻只能有一个线程访问该数据,当这一线程访问结束时其它线程才能对这它进行访问。
同步最多见的方式就是使用锁(Lock) ,也称为线程锁。锁是一种非强制机制,每个线程在访问数据或资源以前,首先试图获取(Acquire)锁,并在访问结束以后释放(Release)锁。在锁被占用时试图获取锁,线程会进入等待状态,直到锁被释放再次变为可用。优化
二元信号量 ui
二元信号量(Binary Semaphore)是一种最简单的锁,它有两种状态:占用和非占用。它适合只能被惟一一个线程独占访问的资源。当二元信号量处于非占用状态时,第一个试图获取该二元信号量锁的线程会得到该锁,并将二元信号量锁置为占用状态,以后其它试图获取该二元信号量的线程会进入等待状态,直到该锁被释放。操作系统
多元信号量
多元信号量容许多个线程访问同一个资源,多元信号量简称信号量(Semaphore),对于容许多个线程并发访问的资源,这是一个很好的选择。一个初始值为N的信号量容许N个线程并发访问。线程访问资源时首先获取信号量锁,进行以下操做:
访问资源结束以后,线程释放信号量锁,进行以下操做:
互斥量
互斥量(Mutex)和二元信号量相似,资源仅容许一个线程访问。与二元信号量不一样的是,信号量在整个系统中能够被任意线程获取和释放,也就是说,同一个信号量能够由一个线程获取而由另外一线程释放。而互斥量则要求哪一个线程获取了该互斥量锁就由哪一个线程释放,其它线程没法释放互斥量。
临界区
临界区(Critical Section)是一种比互斥量更加严格的同步手段。互斥量和信号量在系统的任何进程都是可见的,也就是说一个进程建立了一个互斥量或信号量,另外一进程试图获取该锁是合法的。而临界区的做用范围仅限于本进程,其它的进程没法获取该锁。除此之处,临界区与互斥量的性质相同。
读写锁
读写锁(Read-Write Lock)容许多个线程同时对同一个数据进行读操做,而只容许一个线程进行写操做。这是由于读操做不会改变数据的内容,是安全的;而写操做会改变数据的内容,是不安全的。对同一个读写锁,有两种获取方式:共享的(Shared)和独占的(Exclusive)。当锁处于自由状态时,试图以任何一种方式获取锁都能成功,并将锁置为对应的状态;若是锁处于共享状态,其它线程以共享方式获取该锁,仍然能成功,此时该锁分配给了多个线程;若是其它线程试图如独占的方式获取处于共享状态的锁,它必须等待全部线程释放该锁;处于独占状态的锁阻止任何线程获取该锁,不论它们以何种方式。获取读写锁的方式总结以下:
读写锁的状态 | 以共享方式获取 | 以独占方式获取 |
---|---|---|
自由 | 成功 | 成功 |
共享 | 成功 | 等待 |
独占 | 等待 | 等待 |
一个函数被重入,表示这个函数没有执行完成,因为外部因素或内部调用,又一次进入该函数执行。一个函数要被重入,只有两种状况:
一个函数被称为可重入的,代表该函数被重入以后不会产生任何不良后果。举个例子,以下这个sqr函数是可重入的
int sqr(int x) { return x*x; }
一个函数要称为可重入的,必须包含这几个特色:
可重入是并发安全的强力保障,一个可重入的函数能够在多线程环境下放心使用。
以上总结参考了如下内容: