一、线程基本概念
1、进程与线程区别
进程:系统中程序执行和资源分配的基本单位 。每个进程有自己的数据段、代码段和堆栈段 。 进程之间切换的话,需要进行上下文的切换,开销比较大。
线程:线程是操作系统能够进行运算调度的最小单位 。每个进程至少都有一个 main线程, 它与同进程中的其他线程共享进程空间:堆代码、数据 文件描述符、信号等 , 只拥有少量的栈空间, 大大减少了上下文切换的开销。线程也将其称为轻量级的进程。
线程和进程在使用上各有优缺点: 线程执行开销小, 占用的 CPU 少,线程之间的切换快,但不利于资源的管理和保护 而进程正相反 。
内核空间:被所有的进程所共享的。
用户态空间:每个进程在运行的时候,都会有自己的用户态空间。
2、线程的分类
用户线程:运行在用户态的线程,称为用户线程。
内核线程:运行在内核态的线程,称为内核线程。
用户态切换到内核态,可以使用系统调用。
二、线程的常用函数
NPTL线程库
1、线程的创建(==重要==)
1 |
|
2、线程的退出
1 |
|
3、线程的等待(==重要==)
1 |
|
4、获取线程id
1 |
|
5、线程的取消(杀死)
1 |
|
取消的时候,有一个取消点的概念。哪些函数具备取消点,可以使用man 7 pthreads查看。
三、面向对象的线程封装
1、类图
2、代码难点
2.1、threadFunc必须是静态的
2.2、传递this指针
四、基于对象的线程封装
1、类图
2、代码难点
2.1、回调函数的注册
2.2、回调函数的执行
五、互斥锁
1、互斥锁的类型
1 |
|
2、互斥锁的初始化
1 |
|
3、互斥锁的销毁
1 |
|
4、互斥锁的上锁与解锁
1 |
|
==总结:互斥锁的函数,成功返回的是0,失败返回的是非0的值,以及错误码。==
互斥锁使用总结:
1、上锁一定要注意解锁,不然有可能会发生阻塞状态(也就上锁与解锁一定要成对出现)
2、两次上锁,会让程序处于阻塞状态,但是可以多次执行尝试上锁(也要注意,一定要解锁)
3、锁只有上锁与解锁状态,没有其他状态
4、如果锁处于上锁状态,那么是不能进行销毁的。也就是只有处于解锁状态的时候,才能销毁。
六、条件变量
1、条件的类型
1 |
|
2、条件变量的初始化
1 |
|
3、条件变量的销毁
1 |
|
4、条件变量的等待
1 |
|
5、条件变量的通知
1 | //至少唤醒一个等待等待在条件变量上的线程 |
==总结:条件变量的函数,成功返回的是0,失败返回的是非0的值,以及错误码==
一、问题回顾
1、线程与进程的区别?
2、线程的常用函数?
3、面向对象线程封装的设计与代码难点?
4、基于对象的线程封装的设计与代码难点?
5、互斥锁的常用函数以及所用需要注意那些点?
6、条件变量的常用函数有哪些?
二、条件变量的使用
唤醒操作一定要在wait之后,不然wait在条件变量上的线程是无法被唤醒的。
三、面向对象生产者与消费者封装
1、原理图
2、类图设计
3、代码难点(==重要==)
3.1、防止死锁
3.2、虚假唤醒
3.3、TaskQueue中的push与pop完整思路
3.4、生产者与消费者的run方法
3.5、禁止复制
一、问题回顾
1、面向对象的PC原理?类图的设计是什么?
2、如何防止死锁?如何防止虚假唤醒?禁止复制有哪些方式?
3、如何解析源码?
4、基于对象的PC如何实现?
5、面向对象线程池的类图设计回顾?
二、基于对象的PC
1、类图
2、代码难点
2.1、生产者与消费者的run的改造
2.2、测试代码
三、线程池
三、面向对象线程池封装
1、使用场景
如果任务比较少的话,可以来一个任务就对应创建一个线程,当任务执行结束之后,就将线程回收。如果任务量比较大的时候,还这样操作,那么线程的创建与销毁就比较频繁,而线程的创建与销毁也是会耗费资源的,所以在任务来之前,就创建一部分线程,任务到来之后,就放在任务队列中,线程池中的子线程在任务队列中拿任务,只要任务没有执行完毕,那么子线程就一直拿任务,执行任务。