一、线程概念理解
1. 何为线程——线程与进程的区别
进程简单说就是一个程序的执行过程,有了这个概念,就可以覆盖系统编程的大部分情景了。那么线程的出现又有什么意义呢?其实程序的一段执行过程确实可以叫做进程,但是真正的执行对象并不是进程,而是线程(轻量化的执行单元)。
大体来说,进程相当于资源分配的基本单位,而线程是调度的基本单位。一个进程拥有虚拟地址空间、信号资源、文件描述符表等等资源,线程只是进程一部分,是进程真正的执行流。对于 CPU 而言,它并不认识进程,它只认执行流,每个线程被创建后可以执行指定代码片段,这样一来,一个进程就可以被拆分为多个执行流,既能并发处理任务,又能大幅降低上下文切换的开销,从而提升整体运行效率。进程和线程的对应关系是 1:n,在之前所谓的进程其实大部分指的是单线程进程。
联系前置知识:所谓的进程切换(时间片)、调度算法、调度队列等,实质都是对线程而言而不是进程。
2. 线程的特点
2.1 共享进程资源
线程作为进程的一部分,共享了整个进程的虚拟地址空间。信号处理方法等资源,这样的设计大大降低了线程切换时的开销(无需进行大量资源载入),这也是线程的核心设计特色。
2.2 有独立的执行上下文与栈空间
作为进程真正的执行流,线程的执行遵循调度队列、时间片轮切等原则,因此需要通过上下文的保存进行线程之间的轮切,**同时也就意味着线程具有独立的 PCB 结构体进行执行上下文保存。**栈私有是线程独立执行函数调用的基础。
2.3 同进程内线程容易通信
由于同进程内线程具有共享进程资源的特性,也就意味着线程间不存在进程间通信的最大问题:看到同一份资源,因此线程间很容易实现通信。
2.4 一个线程崩溃,全部崩溃
当某一个线程发生异常的时候,会触发硬件向进程发送信号导致进程中断退出,进程退出也就意味着线程全部退出,导致所有线程崩溃。
3. 线程优缺点
优点
• 创建一个新线程的代价要比创建一个新进程小得多 • 与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多 ◦ 最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。 ◦ 另一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲 TLB(快表)会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题,当然还有硬件 cache。 • 线程占用的资源要比进程少 • 能充分利用多处理器的可并行数量 • 在等待慢速 I/O 操作结束的同时,程序可执行其他的计算任务 • 计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现 • I/O 密集型应用,为了提高性能,将 I/O 操作重叠。线程可以同时等待不同的 I/O 操作。
缺点
• 过多线程创建可能导致频繁线程轮切,反而降低效率。 ◦ 一个很少被外部事件阻塞的计算密集型线程往往无法与其它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。 • 由于线程间共享虚拟空间,健壮性降低 ◦ 编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。 • 缺乏访问控制 ◦ 进程是访问控制的基本粒度,在一个线程中调用某些 OS 函数会对整个进程造成影响。 • 编程难度提高 ◦ 编写与调试一个多线程程序比单线程程序困难得多
二、相关接口及基础用法
pthread_create

功能:创建一个新的线程
原型:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg);










