线程概念
什么是线程
- 在一个程序里的一个执行路线就叫做线程(thread)。
- 更准确的定义是:线程是“一个进程内部的控制序列” 一切进程至少都有一个执行线程
- 线程在进程内部运行,本质是在进程地址空间内运行
- 在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化
- 透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程 执行流
LWP:light weight process 轻量级进程
- 进程:独立地址空间,拥有 PCB
- 线程:也有 PCB,但没有独立的地址空间(共享) 区别:在于是否共享地址空间。
独居(进程);合租(线程)。
Linux 下:
线程:最小的执行单位
进程:最小分配资源单位,可看成是只有一个线程的进程。
一个进程创建多少个线程,他们都共用一块地址空间,但是线程越多,占用cpu越多,也就是cpu分的时间片越多,效率越高。因为线程是最小的执行单位,要被执行,必须要用cpu。
Linux内核线程实现原理
类 Unix 系统中,早期是没有“线程”概念的,80 年代才引入,借助进程机制实现出了线程的概念。因此在这 类系统中,进程和线程关系密切。
- 轻量级进程(light-weightprocess),也有 PCB,创建线程使用的底层函数和进程一样,都是 clone
- 从内核里看进程和线程是一样的,都有各自不同的 PCB,但是 PCB 中指向内存资源的三级页表是相同的
- 进程可以蜕变成线程
- 线程可看做寄存器和栈的集合
- 在 linux 下,线程最是小的执行单位;进程是最小的分配资源单位
线程1和线程2程序内部执行的函数不会一样,所以对应的栈不一样。
Linux操作系统中cpu划分时间轮片的依据
查看 LWP 号:ps –Lf pid
** 查看指定线程的 lwp 号。不是线程ID**
注意
- 对于进程来说,相同的地址(同一个虚拟地址)在不同的进程中,反复使用而不冲突。原因是他们虽虚拟地址一样,
- 进程的页目录、页表、物理页面各不相同。相同的虚拟地址,映射到不同的物理页面内存单元,最终访问不同的物理页 面。
- 线程不同。两个线程具有各自独立的 PCB,但共享同一个页目录,也就共享同一个页表和物理页面。所以 两个 PCB 共享一个地址空间。 实际上,无论是创建进程的 fork,还是创建线程的 pthread_create,底层实现都是调用同一个内核函数 clone。
如果复制对方的地址空间,那么就产出一个“进程”;如果共享对方的地址空间,就产生一个“线程”。 - 因此:Linux 内核是不区分进程和线程的。只在用户层面上进行区分。所以,线程所有操作函数 pthread_ 是 库函数,而非系统调用。*
线程共享资源
- 文件描述符表
- 每种信号的处理方式
- 当前工作目录
- 用户 ID 和组 ID
- 内存地址空间 (.text/.data/.bss/heap/共享库)没有stack
线程非共享资源
- 线程 id
- 处理器现场和栈指针(内核栈)
- 独立的栈空间(用户空间栈)
- errno 变量
- 信号屏蔽字
- 调度优先级
线程优、缺点
优点:
- 提高程序并发性
- 开销小
- 数据通信、共享数据方便
- 创建一个新线程的代价要比创建一个新进程小得多
- 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多
- 线程占用的资源要比进程少很多
- 能充分利用多处理器的可并行数量
- 在等待慢速I/O操作结束的同时,程序可执行其他的计算任务
- 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现
- I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作。
缺点:
- 库函数,不稳定 ,进程中时库函数
- 调试、编写困难、gdb 不支持
- 对信号支持不好 优点相对突出,缺点均不是硬伤。
- 线程间缺乏访问控制,编码难度更高
- 线程健壮性更低
Linux 下由于实现方法导致进程、线程差别不是很大。