在Linux学习中,我们经常遇到线程、进程、多线程、内核线程等概念。
虽然我们都清楚从内核的角度来说,并没有线程的概念。Linux把所有的线程都当成进程来实现。内核并没有准备特别的调度算法或是定义特别的数据结构来表征线程。(来源LKD)
但是究其实质,只是说Linux利用了特别的机制实现了线程机制。但是我们还是很有必要去学习线程的本质,以及它与进程的区别。下面我们从几个方便进行介绍,帮助大家梳理进程、线程的区别于联系。
线程机制是现代编程技术常用的一种抽象概念。该机制提供了在同一程序内共享内存地址空间运行的一组线程。这些线程可以共享打开的文件和其他资源;线程机制支持并发程序设计技术,在多处理器系统上,它也能保证真正的并行处理。
线程,是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位(它是一个比进程更小,能独立运行的基本单位) 。
线程基本不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
在多线程OS中,通常是在一个进程中包括多个线程,每个线程都是作为利用CPU的基本单位,是花费最小开销的实体
在Unix环境里的线程有如下的特点:
进程是程序执行时的一个实例。你可以把它看作充分描述程序已经执行到何种程度的数据结构的汇集。从内核观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)实体,同时它也是系统调度的基本单位。多进程之间是拥有独立的内存单元,每个进程有独立的堆栈段、代码段、数据段。
在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。同一个进程中的多个线程可以并发执行,多线程之间拥有共享的内存单元,这样以提高执行效率。
进程是线程的容器,进程提供资源、内存。里面的线程利用进程的资源,内存执行代码。
进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。一个程序至少包含一个进程,一个进程至少包含一个线程。
区别和联系:
1、进程是独立运行的实体,有独立的资源分配,某进程内的线程在其他进程不可见;
2、同一进程的线程之间共享进程的资源;
3、所有的进程至少有一个执行线程;
4、线程的创建和切换代价比进程的小;
5、在多线程OS中,进程不是一个可执行的实体。
线程间的通信方法:
1、同一进程的线程之间通信的最简单办法就是使用全局变量;
2、不同进程的线程之间通信需要通过下面进程间的通信来实现;
进程间的通信方法:
1、管道
2、信号量
3、共享内存
4、消息队列
5、套接字
在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,内核无需单独复制进程的内存空间或文件描述符等等,它们彼此之间使用相同的地址空间,共享大部分数据,使得线程创建比新进程创建快上十到一百倍。因为这一点,可以大量使用线程而无需太过于担心带来的CPU 或内存不足。
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
前面说了很多关于线程和进程的区别与联系,明白了这些。我们具体来看Linux下线程、多线程的实现以及介绍内核线程的概念。
在Linux下,线程仅仅被视为一个与其他进程共享某些资源的进程。每个进程都拥有唯一隶属自己的tast_struct,所以在内核中,它看起来是一个普通的进程(只是线程和其他一些进程共享某些资源,如地址空间)。(LKD)
Linux使用轻量级进程对多线程应用程序提供了更好的支持。两个轻量级进程几个上可以共享一些资源,诸如地址空间、打开的文件等。只要其中一个修改共享资源,另一个就立即可以查看这种修改。当然,当两个线程访问共享资源时就必须同步自己。
实现多线程应用程序的一个简单方式就是把轻量级进程与每个线程关联起来。这样,线程之间就可以通过简单地共享内存地址空间、同一个打开文件集等来访问相同的应用程序数据机构集;同时,每个线程都可以由内核独立调度,以便一个睡眠的同时另一个仍然是可以运行的。(ULK)
内核线程
内核经常需要在后台执行一些操作。这种任务可以通过内核线程完成。内核线程和普通进程间的区别在于内核线程没有独立的地址空间。它们只在内核空间运行,从不切换到用户空间去。内核进程和普通进程一样,可以别调度,也可以被抢占。内核线程只能由其他内核线程来创建。(LKD)
参考文献:
《深入理解Linux内核》
《Linux内核设计与实现》