1 线程相关概念
1.1 为什么要引入线程
不同进程之间切换,系统开销很大,为了提高效率很多操作系统(Windows和Linux)都引入了轻量级进程LWP,即线程。
因为同一进程下的线程共享相同的地址空间,所以(同一进程下的)线程之间切换系统开销小效率高。
在Linux下编程,不严格区分进程与线程,将它们都视为任务,用结构体task_struct描述。
1.2 线程定义
共享相同地址空间(可理解为在同一进程下)的多个任务,我们称每个任务为一个线程。
1.3 线程优点
1、提高任务切换的效率;
2、避免额外的TLB和cache(高速缓存)的刷新。
1.4 同一进程下多个线程共享的资源
1、可执行的指令;
2、静态数据;
3、进程中打开的文件描述符;
4、当前的工作目录;
5、用户ID;
6、用户组ID。
1.5 同一进程下多个线程私有的资源
1、线程ID(TID)
2、PC(程序计数器)和相关寄存器;
3、堆栈;
4、错误号(errno);
5、优先级;
6、执行状态和属性。
2 线程重点操作函数
当一个进程结束时,其下的所有线程都将结束。线程也是进程,是特殊的进程。pthread线程库提供如下线程重点函数。
2.1 线程创建函数
2.2 线程回收函数
2.3 线程结束函数
3 线程间通信方式
因为同一进程下的线程共享相同的地址空间,所以线程间通信很容易,通过全局变量就可以交换数据。但是多个线程访问共享数据时有可能引起混乱,为了使线程间通信有序高效,引出了线程间通信同步和互斥机制。
3.1 线程同步机制-信号量(灯)
3.1.1 同步定义
同步(synchronization)指的是多个任务按照约定的先后次序相互配合完成一件事情。
同步机制是1968年Edsgar Dijkstra基于信号量的概念提出的。同步机制即可用于线程也可用于进程。
同步机制的实现过程是由信号量来决定线程是继续运行还是阻塞等待。
3.1.2 信号量定义
信号量代表某一类资源,其值表示系统中该资源的数量。信号量是非负整数。
3.1.3 信号量分类
1、无名信号量:主要用于进程内部的线程间通讯(本节讲解重点);
2、有名信号量:可用于进程之间,也可用于线程之间通讯。
3.1.4 信号量的操作访问
信号量是一个受保护的变量,只能通过三种操作来访问:初始化;P操作(申请资源);V操作(释放资源)。
1、信号量初始化
信号量定义后,必须初始化,函数如下:
2、P操作(申请资源)和V操作(释放资源)。
P操作(申请资源)可能引起程序的阻塞,V操作(释放资源)肯定不会引起程序的阻塞。
3.2 线程互斥机制-互斥锁
3.2.1 相关概念
1、临界资源:一次只允许一个任务(进程或线程)访问的共享资源。
2、临界区:访问临界资源的代码。
3、互斥机制的引出:要实现临界资源的保护,就必须实现访问同一临界资源的每个任务的临界区的互斥。互斥机制里最常用的就是互斥(mutex)。
4、互斥锁实现互斥的原理:互斥锁只要两种状态,要不空闲,要不被一个任务持有。任务在访问临界资源前要先申请锁:如果互斥锁空闲,申请就可以成功,任务就可以访问临界资源,但这个任务访问完临界资源后一定要释放互斥锁;如果任务申请互斥锁时,互斥锁被其它任务持有,该任务就得阻塞等待,直到其他任务访问完临界资源释放互斥锁,互斥锁空闲时访问临界资源。