Linux中线程的概念:
首先,Linux中并不存在真在的线程。Linux中的线程是使用进程来模拟的。在一个进程需要同时运行多个执行流时,linux并不是开辟多个线程来执行,而是通过多个进程来模拟多个线程。
Linux中线程的实现原理:
首先先看一下张图:
此时共有4个线程属于同一个进程,他们的task_struct(Linux中为PCB)不同,但是映射的虚拟地址空间和页表是相同的。所以说Linux中的的线程就是——多个PCB映射同一块虚拟地址空间,使得同一个进程中不同的执行流能够同时执行。因此可以总结出同一进程不同线程的资源分配情况:
共享 | 私有 |
虚拟地址空间中的代码段、数据段 | 线程ID |
文件描述符表(一个线程打开了文件,其他线程也可以看到此文件的描述符) | 一组寄存器(储存着此线程的上下文信息,上下文中储存着各种计数器的值,程序计数器和栈指针) |
每种信号的处理方式 | 栈(运行时栈) |
在同一个工作目录下 | errno(线程异常退出时的错误退出码) |
用户ID和线程组ID | 信号屏蔽字 |
调度优先级 |
线程的优缺点:
优点:
-
相比进程,更加节省系统资源(虚拟地址空间、页表、物理内存中的代码和数据都是共享的)。
-
线程间切换,系统的工作量很少(切换进程的时候需要切换进程上下文、地址空间、页表。线程切换只需要切换上下文,也不用切换cache(内存和寄存器之间的一个硬件))。
-
创建一个新线程的代价,比创建一个进程的代价小得多。
-
线程间共享数据更加容易。
-
能够充分利用多处理器的可并行数量。
-
在等待慢速的I/O操作结束的同时,程序可以运行其他的计算任务。
-
计算密集型应用,为了能在多处理器系统上运行,可以将计算分解到多个线程中来实现。
-
I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
缺点:
1.性能损失
一个很少被外部事件阻塞的计算密集型线程往往无法与其他线程共享一个处理器。如果计算密集型线程的数量比可用的处理器多,那么就有可能造成较大的性能损失,这里的性能损失指的是操作系统增加了额外的同步和调度开销,而可用的资源不变。
2.健壮性降低
由于线程是共享同一块虚拟地址空间的,在运行期间,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,也就是说线程之间是缺乏保护的。
3.缺乏访问控制
当在线程中调用某些函数(OS函数,处理signal函数,调用kill/exit函数),可能会导致线程退出,从而使所有的线程都异常退出。
4.编程难度高
线程共用同一块虚拟地址空间,势必在处理多线程时会有访问同一个资源等问题,此时就涉及到共享资源的处理。
线程相关概念:
- Linux中的线程概念只是模拟线程。对于Linux系统来说,并不存在线程一说。因此,线程的概念只有在用户态才有。
- NLWP:当前线程组中的线程个数。
- 进程是资源分配的单位,线程是系统调度的基本单位。
- bash中输入ps -aL | grep your_thread_name (L表示查看线程)此命令可以查看同一进程的所有线程。
- 系统打印出的tid转成16进制之后可以看到,tid本质上来说就是地址。
- LWP:线程又被称作LWP(Light WeightedProcess)轻量级进程。是线程的ID,是使用gettid()函数的返回值。链接线程库函数的时候,需要使用“-Ipthread”选项
- 与线程有关的函数,大多数是以pthread_开头的
- 线程组(tgid):由于线程概念的引入,一个进程可能对应多个PCB,POSIX标准又要求所有的线程在调用getpid函数的时候返回相同的进程ID,所以就有了线程组的概念。
- 用户层面看到的pid,对应的是底层内核中的tgid。而用户层面的tid,对应在内核之中则是pid字段。
- 一个用户态的进程,内部对应着N个PCB,tgid通常是线程组的第一个线程(主线程)
- LWP实则是pid。
- 线程组中的第一个线程,在用户态被称为主线程,在内核中被称为group leader。内核在创建第一个线程的时候,会将线程组的ID值,设置成第一个线程的线程ID,Group_Leader指针则指向自身,即主线线程的进程描述符。
- 线程租内存在一个线程,它的ID等于进程ID,而该线程就是该线程组的主进程。
- 线程没有父子的概念,只有主线程,没有父子线程之分
- 程序开始运行之后,哪个进程先运行由调度机决定,线程也是同理
- pythread_self()函数可以用来获取当前线程自身的tid。
线程的创建与控制:
POSIX线程:
是POSIX的线程标准,它定义了一套创建和操纵线程的一套API,以pthread.h头文件和一个线程库来实现,而且其中的函数均以“pthead_”开头。gcc或g++在链接这些线程函数库的时候,需要使用“-Ipthread”选项(pthread是共享库文件)。