1,为什么会产生或者引入线程呢???
2,程序,进程,线程之间的区别???
3,线程的优缺点,线程的模型(1:1,N:M,N:1)???
程序:完成特定功能的一系列有序指令的集合,我们常常写的C代码就是一个源程序(经过编译,链接,生成可执行 文件,这个可执行文件我们称为程序)
通常这个可执行程序有一定的格式:代码段+数据段
进程:程序的一次动态执行过程,是动态的
因而:为了增加动态性,肯定会增加一些自己的数据结构
代码段+数据段+堆栈段+PCB+上下文信息
PCB:记录了当前进程运行的一些状态(包括是处于就绪状态,还是运行状态,还是等待状态),还包括进 程执行时CPU的状态(运行到哪一个地址,堆栈的sp等一些信息)
另外,进程在推进运行的过程中会调用一些数据,可能中间会产生一些数据保留在堆栈段,所以是动态的,
而程序就不具有这种动态性.
1,源程序编译连接完成后变成可执行程序是保存在磁盘上的,数据一旦初始化是不会改变的;进程是在内核中执行
2,进程有一定的生命周期,是短暂的,只是程序的一次动态执行过程,如果我们将计算机关闭,那么进程自然而然
的就消亡了,但是程序不会(只要保持数据的磁盘,介质不遭受破坏,那么程序就永久性的保存在磁盘当中)
3,新添加的数据结构:堆栈段+PCB+上下文信息
一个进程只能对应一个程序,而一个程序可以对应多个进程(多个实例)
为什么会产生线程???
早期:在OS中一直都是以进程作为能拥有资源和独立运行的基本单位.后来人们又提出了比进程更小的能独立运行
的基本单位-线程(Threads),试图通过它来提高系统内程序并发执行的程序,从而进一步提高系统的吞吐
量.后来多处理机系统得到迅速发展,线程能比进程更好的提高程序的并发执行程序,充分发挥多处理机的优越性.
如果说:在操作系统中引入进程的目的,是为了使多个程序能并发执行,以提高资源的利用率和系统的吞吐量,那么
在操作系统中再引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发行
(进程的两个基本属性:1,进程是一个可拥有资源的独立单位
2,进程同时又是一个可独立调度和分派的基本单位)
所以进程才能成为一个独立运行的基本单位.从而也就构成了进程并发执行的基础
然而,为了能并发执行,系统还必须进行一下一系列的操作....
1,创建进程
系统在创建一个进程时,必须为它分配其所必须的,除处理机以外的所有资源,如:内存设备,I/O设备
,以及相应的PCB
2,撤销进程
系统在撤销进程时,又必须先对其所占有的资源执行回收操作,然后在撤销PCB
3,进程切换
对进程进行切换时,由于要保留当前进程的CPU环境和设置新选中进程的CPU环境,因而须花费不少的时 间
换言之:由于进程是一个资源的拥有者,因而在创建,撤销,切换中,系统必须为之付出较大的时空开销.正因如 此,在系统中所设置的进程,其数目不宜过多,进程切换的频率也不宜过高,这也就限制这并发程度的进一步提高
那么如何能使多个程序更好的并发执行同时又尽量减少系统的开销,我们的先辈们一直在苦苦探寻着,,,后来,
不少学者发现能不能:将进程的上述两个属性分开,由操作系统分开处理亦即对于作为调度和分配的基本单位,不
同时作为拥有资源的单位,以做到"轻装上阵",而对于拥有资源的基本单位,又不对其进行频繁的切换.
正是在这种思想的指导下:形成了线程的概念.......
随着VLSI技术和计算机体系结构的发展,出现了对称多处理机(SMP)计算机系统.它为提高计算机的运行
速度和系统吞吐量提供了良好的硬件基础.但要使多个CPU很好的协调运行,充分发挥它们的并行处理能力,以提
高系统性能,还必须配置性能良好的多处理机OS.但利用传统的进程概念和设计方法,已难以设计出适合于smp
结构的计算机系统的OS.因为进程"太重",致使实现多处理机环境下的进程调度,分派,切换时,都需要花费
较大的时间和空间开销.如果在OS中引入线程,以线程作为调度和分派的基本单位,则可以有效的改善多处理机系
统的性能.因此,一些主要的OS(UNIX,Windows)都进一步对线程技术做了开发,使之适用于SMP的计
算机系统.
线程与进程的比较:
线程具有许多传统进程所具有的特征:又称为轻型进程或进程元,相应的传统进程称为重型进程,传统进程相当于只
有一个线程的任务.在引入线程的操作系统中,通常一个进程都拥有若干个线程,至少也有一个线程.我们可以从
调度性,并发行,系统开销,拥有资源等方面进行比较...
1,调度性
在传统的操作系统中,作为拥有资源的基本单位和独立调度,分派的基本单位都是进程.但是在引入线程的操作
系统中,则把线程作为调度和分派的基本单位,而进程作为资源拥有的基本单位.把传统进程的两个属性分开, 使线程基本上不拥有资源,这样线程便能轻装前进,从而可显著的提高系统的并发程度.在同一进程中,线程的
切换不会引起进程的切换,但是,从一个进程中的线程切换到另一个进程中的线程使,将会引起进程的切换
2,并发行
在引入线程的操作系统中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也是可以并发执
的,使得操作系统具有更好的并发行,从而更加有效的提高系统资源的利用率和系统的吞吐量.例如:在一个
未引入线程的单CPU操作系统中,若仅设置一个文件服务进程,当该进程由于某种原因而被阻塞时,便没有
其它的文件服务进程来提高服务.在引入线程的操作系统中,则可以在一个文件服务进程中设置多个服务线程
.当第一个线程等待时,文件服务进程中的第二个线程可以继续运行,以提供服务.同理,这样的方法可以显著
的提高文件服务的质量和系统的吞吐量.....
3,拥有资源
不论是传统的操作系统,还是引入了线程的操作系统.进程都可以拥有资源.是系统中拥有资源的一个基本单
位.一般而言,线程自己不拥有系统资源(也有一点儿必不可少的资源),但它可以打开访问其隶属进程的资源
,即一个进程的代码段,数据段,及所拥有的系统资源,如:已经打开的文件,I/O设备等,可以供该进程中
所有线程所共享.
4,系统开销
在创建或撤销进程时,系统都有为之创建和回收进程控制块,分配和回收资源,如内存空间和I/O设备等,
操作系统所付出的开销明显大于线程创建或撤销时的开销.类似的,在进程切换时,涉及到当前进程CPU
环境的保存及新被调度运行进程的CPU环境的设置,而线程的切换则仅需保存和设置少量的寄存器内容,不涉 及到存储器管理方面,所以就切换代价而言,进程也是远高于线程的.此外,由于一个进程中的多个线程具有
多个相同的地址空间,在同步和通信的实现方面线程也比较容易.在一些操作系统中,线程的切换,同步和通信
都无须内核的干预....
线程的属性:
在多线程OS中,通常是一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费开销最小的实体.线程具有以下属性:
1,轻型实体.线程中的实体基本上不拥有系统资源,只是有一点是必不可少的,能保证其独立运行的资源.如:在
每个线程中都应具有一个用于控制线程运行的线程控制块TCB,用于指示被执行指令序列的程序计数器,保留
局部变量,少数状态参数和返回地址等的一组寄存器和堆栈....
2,独立调度和分配的基本单位
在多线程OS中,线程是能独立运行的基本单位,因为也是独立调度和分配的基本单位.由于线程很轻,因此
线程的切换非常迅速且开销小
3,可并发执行.一个进程中的多个线程可以并发执行,甚至允许在一个进程中的所有线程都能并发执行;同样,不
同进程中的线程也能并发执行
4,共享进程资源.在同一个进程中的各个线程都可以共享该进程所拥有的资源.这首先表现在所有线程都具有相同
的地址空间(进程的地址空间).这意味着线程可以访问可以访问该地址空间中的每一个虚地址.此外,还可以
访问进程所拥有的已打开文件,定时器,信号量机构等....
线程的状态:
1,状态参数.在OS中的每一个线程都可以利用线程标识符和一组状态参数进行描述
状态参数通常有这样几项:1,寄存器状态,它包括程序计数器PC和堆栈指针中的内容;2,堆栈,在堆栈中
通常保存有局部变量和返回地址;3,线程运行状态,用于描述线程处于何种运行状态;4,优先级,描述
线程执行的优先程度;5,线程专有存储器,用于保存线程自己的局部变量拷贝;6,信号屏蔽,即对某些
信号加以屏蔽
2,线程的运行状态.如图传统的进程一样,在各线程之间也存在着共享资源和相互合作的制约关系.致使线程在运 行也具有间断性.
1,执行状态,表示线程正获得处理机而运行;2,就绪状态,线程具备了各种执行条件,一旦获得CPU便可
执行的状态;3,阻塞状态,线程在执行某件事而受阻,处于暂停执行的状态.
线程的创建和终止
在多线程OS环境下,应用程序在启动时,通常仅有一个线程在执行,该线程被人们称为"初始化线程".它可根据
需要再去创建若干个线程.在创建新线程时,需要利用一个线程创建函数(或系统调用),并提供相应的参数,如:
指向线程主程序的入口指针,堆栈的大小,以及用于调度的优先级等...在线程创建函数执行完后,将返回一个线
程标识符供以后使用...
如同进程一样:线程也是具有生命期的.终止线程的方式有两种:一种是在线程完成了自己的工作后自愿退
出;另一种是线程在运行中出现错误或由于某种原因而被其它线程强行终止.但是但是(有些线程,主要是系统线
程,在它们一旦被建立起来之后,便一直运行下去而不再被终止.在大多数OS中,线程被终止后并不立即释放它
所占有的资源,只有当进程中的其它线程执行了分离函数后,被终止的线程才与资源分离,此时资源才能被其它线
程利用)
虽已被终止但尚未释放资源的线程,仍可以被需要它的线程所调用,以使被终止的线程重新恢复执行.为此,调
用者线程须调用一条被称为"等待线程终止"的连接命令,来与该线程进行连接.如果在一个调用者线程调用"等待
线程终止"的连接命令试图与指定线程连接时,若指定线程尚未被终止,则调用连接命令的线程将会阻塞,直至指定
线程被终止后才能实现它与调用者线程的连接并继续执行;若执行线程已经被终止,则调用者线程不会被阻塞而是继
续执行....
多线程OS中的进程
在多线程OS中,进程是作为拥有系统资源的基本单位,通常的进程都包含多个线程并为它们提供资源,但此时的进
程就不再作为一个执行的实体.多线程OS中的进程有一下属性:
1,作为系统资源分配的单位.在多线程OS中,仍是将进程作为系统资源分配的基本单位,在任一进程中所拥有的
资源包括受到分别保护的用户地址空间,用于实现进程间和线程间同步和通信的机制,已打开的文件和已申请的
I/O设备,以及一张由核心进程维护的地址映射表,该表用于实现用户程序的逻辑地址到其内存物理地址的映
射
2,可包括多个线程.通常,一个进程都包含多个相对独立的线程,其数目可多可少,但至少也要有一个线程,由进
程为这些(个)线程提供资源和运行环境,使这些线程可并发执行.在OS中所有的线程都只能属于某一个特定
的进程
3,进程不是一个可执行的实体.在所线程OS中,是把线程作为独立运行的基本单位,所以此时的进程已不再是一
个可执行的实体.虽然如此,进程仍具有与执行相关的状态.例如:所谓进程处于"执行"状态,实际上是该进
程中的某线程正在执行.此外,对进程所施加的与进程状态相关的操作,也对其线程起作用.如:在把某个进程
挂起时,该进程中的所有线程也都将被挂起;又如,在把某进程激活时,属于该进程的所有线程也都被将激活.
线程:一个程序里的一个执行路线.更准确的来说:一个线程是一个进程内部的控制序列(一些指令)
单线程:只有一个控制序列; 多线程:多个控制序列
一个进程至少都有一个执行线程
每一个进程都具有4GB的地址空间.......
线程在进程内部共享地址空间,打开文件描述符等资源.但是线程也有其私有的数据信息,包括:
1,线程号(thread ID):每个线程都有唯一的线程号一一对应.
2,寄存器(包括程序计数器和堆栈指针,IP,SP,通用寄存器,状态寄存器等等)
3,堆栈(因为线程内部也有一些自己的局部变量,要保存在线程的堆栈里面)
4,error(每个线程都有一个错误代码,并不是所有线程共享整个进程的一个错误码的)
5,信号状态(每个线程也有自己对信号的处理的状态,包括信号是如何屏蔽的(Signal Mask))
6,优先级
也就是说:其它的数据是共享的,其它的线程改变了某个数据的话,那么其它线程获取的数据也是改变后的
fork创建一个新的进程和ptrhread_create创建一个线程的区别:
1,当一个进程调用fork的时候,会创建一个新的进程(刚才进程的拷贝),两个进程几乎是一模一样的,并且新的进
程有自己独立的地址空间(单独的4GB),新的进程将拥有自己的变量,不能跟原进程共享全局变量(进程跟进
程之间是没有所谓的全局变量之说的,,,,当然,如果进程之间要共享数据的话,那么是可以有别的机制的
(共享内存)),新的进程拥有自己的PID,
2,而我们创建一个新的线程呢????
要跟其它的线程共享全局变量(也就算4GB的地址空间),共享当前的进程的资源,打开的文件描述符,信号处
理器,以及当前工作目录的状态
当然新的线程会有自己的局部变量保存在自己的堆栈。。。。
线程的优点:
1,线程占用的资源要比进程少的多(只占用一些执行线程所必要的信息,因而线程是程序执行的最小单位,进程是
资源分配的最小单位)
2,根据资源占用情况,所以创建一个新的线程要比创建一个新的进程所多花费的代价小的多
3,进程之间的切换也比线程的切换小很多,也就是说:进程的切换,操作系统要处理很多东西
4,多线程的程序往往能很好的利用多处理机的并发性能
5,一个线程在等待慢速I/O结束的同时,此刻,另外一个线程可以计算其它的计算任务;
而对于单线程而言的话,一旦线程阻塞,那么是不能执行其它的认为的
6,对于计算密集型任务或I/O密集型任务,多线程都能很容易的提高性能
对于一个高性能的分布式网络服务器而言,往往要处理很大并发的网络I/O(慢速的I/O),那么,这个时候,我们
就可以用一定的线程来处理这些I/O(利用将I/O操作重叠,一个线程可以等待好几个I/O),可以处理百万级的并发
,可能把上面的这些线程放到一个线程池中,(也就算线程池中的线程来处理大量的I/O),一个线程可以等待多
个不同的I/O
那么线程的缺点呢????
1,性能损失(大家可能很疑惑,我们引入线程的目的不就是为了减少进程所引发的性能损失吗???,为什么还说
线程的性能的损失呢???)
其实,仅仅是从另外一个层面来看待问题的:
假设一个程序有很多计算密集型线程,那么这些计算密集性的线程很难与其它线程共享同一个处理器,因为很少
被外部事件阻塞,,,往往是独享某一个处理器的,
计算密集型线程意味着要占用cpu,I/O密集性线程意味着要占用I/O(可以让出cpu)
假如:我们此刻有10个计算密集型线程,但是我们仅仅是4核的,意味着这10个最多有4个能调度到这4个cpu
上来,那么其它6个线程就无法运行了,如果这4个不让出cpu的话,那么意味着其它6个无法执行,如果
这4个让出cpu的话,那么就意味着要增加一些额外的调度开销。。。。需要在这些线程之间进行切换,
并且这些线程还需要同步,配合完成一些任务。
2,健壮性的降低
多线程程序共享4GB的地址空间,那么如果因为共享了一个不该共享的变量,对这个变量进行破坏,会影响到其
它线程,换句话说:一个线程的崩溃,可能会使整个进程都崩溃,因为其它线程也无法正常的工作了
,而进程与进程之间是受保护的,因为受到一个硬件MMU(内存管理单元的保护),一个进程不会随意的破坏
另外一个进程的地址空间
3,缺乏访问控制
一般来说:进程是访问控制的基本粒度,在一些线程中呢,调用一些OS函数会对整个进程产生影响
如:一个线程当中,更改了当前的工作目录,会影响到其它线程,因为工作目录是进程所竞争到的资源,但是
线程是共享这些资源的,一旦某一个线程更改这些数据,其它线程也随之发生改变,因而是缺乏高精度的
访问控制的
4,编程难度更加提高
编写一个多线程的程序比编写一个单线程程序困难的多。。。。
(线程的模型)线程调度竞争范围:
操作系统提供了各种模型,用来调度应用程序创建的线程
1,线程调度竞争范围:主要是线程在调用cpu时间片上的不一样,是以进程调度范围,还是以系统调度范围
进程竞争范围:各个线程在同一进程竞争“被调度的cpu时间片”,不直接和其它进程中的线程来竞争,
也就是说:各个进程相互竞争cpu时间片,分享给内部的线程竞争
系统竞争范围:线程直接和系统内的其它线程竞争
2,线程的模型
线程的竞争范围不同也导致了线程的模型的不同
1,N:1用户线程模型(实际上是早期线程的实现,早期内核并没有真正实现线程,是借助进程来实现的,系 统当中并没有提供线程的支持,里面提到的kernel threads实际上就算进程)
线程的实现是建立在进程控制机制上的,由用户空间的程序块来管理。OS内核完全不知道线程的概念,
这样的线程称为“用户空间线程”。
这些线程工作在进程竞争范围。。。。。。
内核不干涉线程的任何生命活动(内核并不知道线程的存在,内核不支持线程,只支持进程),因而不干涉
同一进程中线程环境的切换,一个进程当中的多个线程只能调度到一个cpu(当进程抢夺来时间片,该进 程中有两个线程,其中一个阻塞,另外一个也不会执行的),限制了可用的并行总量
如果某个线程执行了阻塞式的操作(如:read),那么进程中的其它线程都会阻塞,直到那个操作结束
,为此,一些线程的实现是为这些阻塞式函数提供包装器,用非阻塞版本代替这些系统调用,以消除这种限 制
2,1:1核心线程模型
操作系统已经对线程提供了支持,应用程序创建的每一个线程都由一个核心线程直接管理
也就是说:用户线程跟核心线程是1:1的关系。。。。两个用户线程对应两个核心线程,可用调用两个
cpu,因此也就解决来不能充分利用多处理器可变形的问题。。。。
是在系统范围竞争来实现的,,每个线程都能竞争一个cpu时间
但是,这种线程的创建和调度都是由内核来完成的,因而开销很大,但是一般来说,也比进程的开销小
3,N:M混合线程模型
提供了两级控制,首先将用户线程映射为系统的可调度体以实现并行,这个可调度体称为轻量级进程
(LWP:light weight process),比刚才所说的核心线程要更加轻便一些,
轻量级线程再一一映射到核心线程
我们如今的POSIX用的就是这种