21复习的内容
生产者与消费者模型
针对的场景:在一个程序中既有数据的产生又有数据的处理的这种逻辑场景
模型实现:
生产者线程,产生数据。消费者线程,处理数据。
中间通过线程安全的缓冲区实现交互。
好处:解耦合(减少模块之间的依赖性,提高程序的独立性),支持并发(指应用能
够交替执行不同的任务,其实并发有点类似于多线程的原理),支持忙闲不均
实现:俩类线程的创建+线程安全的任务队列
信号量
1、本质
计数器+pcb等待队列
2、操作
P操作:对计数器进行计数判断,计数-1;如果<=0则阻塞执行流,否则返回正确。
V操作:计数+1,唤醒一个pcb等待队列中的执行流
3、作用
实现进程或线程间的同步和互斥。
4、互斥
将计数器初始化为1,表示资源只有一个。
在访问资源之前进行P操作,访问资源完毕后进行V操作,模拟实现加锁与解锁
5、同步
通过计数器对已有资源进行计数。
在访问资源之前进行P操作,访问资源完毕后进行V操作。
6、接口
P操作:sem_t / sem_init / sem_wait & sem_timewait & sem_trywait
V操作:sem_post / sem_destroy
锁的种类
可重入锁与不可重入锁,乐观锁与悲观锁,自旋锁,读写锁。
线程池
一个或多个线程+线程安全的任务队列
工作线程不断的从任务队列中取出任务进行处理。
1、适用场景
有大量请求需要并发处理的场景。
2、优点
- 线程池中的线程数量以及缓冲区大小有最大线程,能够避免资源耗尽系统崩溃的风险
- 避免了大量线程的创建及销毁所带来的时间成本
3、实现
创建一堆工作线程,以及一个线程安全的任务队列
线程安全的单例模式
1、应用场景
一个类只能实例化一个对象的场景。
2、优点
避免同一时刻不同对象可能存在不同数据的不统一情况,以及统一管理思想。
3、实现
- 一个类只能实例化一个对象
- 提供统一接口访问
4、饿汉
资源的静态化,对象在程序起始阶段完成构造,构造函数私有化
class singleton{
private:
T data;
static singleton_eton;//static
singleton(){}
public:
static singleton *get_instance()//static
{
return &_eton;
}
};
singleton singleton::_eton;//静态对象需要在类外定义
优点:在构造对象时不需要考虑考虑线程安全的问题。
缺点:程序初始化时间比较长。
5、懒汉
延迟加载的思想,程序初始化速度快。
class singleton {
private:
static singleton* _eton;
static std::mutex_mutex;
singleton(){}
public:
static singleton* get_instance() {
_mutex.lock();
if (_eton == NULL) {
_mutex.lock();
if (_eton == NULL) { _eton = new singleton(); }
_mutex.unlock();
}
return _eton;
}
};
- 定义静态对象指针
- 构造函数私有化
- 加锁保护对象构造过程
- double check提高效率
- volatile修饰,防止编译器过度优化