Linux学习------多线程(4)-----线程应用

线程池

1.概念:

  • 一种线程的使用模型,由于线程的过多,会带来过度的调度开销,对于线程的创建和线程的等待,会有大量的时间以及效率的丢失,这样会大大的折损效率,而线程池的使用可以解决这一问题,线程池维护着多个线程,通过去等待客户所分发的资源并且可以并发执行任务。这大大的避免了线程的创建以及等待的时间浪费的代价。 线程池不仅保证内核的充分利用,也能防止过分的调度。可用的线程数量根据情况而定。

①:一个任务处理的成本:
线程的创建时间+任务的处理时间+线程的等待时间 = 总耗时。
而如果任务处理的时间比较短,那么相较于线程创建和等待时间就较长,那么就大大浪费了时间。
②:风险:若线程无限制,那么在峰值的压力之下,总会有资源耗尽系统崩溃风险。

说白了:线程池,就是创建好一堆的进程,然后创建一个消息队列,这些进程等待着消息队列中的消息,有消息就处理,没有就阻塞等待。

2.线程池的应用场景:

  • 需要大量线程完成任务,并且处理时间要短。
  • 对性能要求高。
  • 接收突发性的大量请求,但不至于让服务器因此产生大量的线程的应用。

3.线程池模拟实现如下:

在这里插入图片描述
其中:我们设置ThreadTask这个类的意义,就是让我们的线程不只是以一种方式去处理这个任务,因为对于线程池,他应该是拿到函数,并且拿到参数去处理的,不可能只设定一个函数去让他执行,如果这样,那么线程池就有点局限了。

单例模型

1.概念:就是对于一个类,他只能实例化出一个对象,提供一个访问接口。(一个资源在内存中只能有一份)

2.目的:

  • 节省内存空间。
  • 防止数据二义混淆。(多种数据在同一时刻的不同体现)

对于整个单例模型,它一共分为以下两种模型:

饿汉模型

1.概念:资源提前就全部加载初始化完,用的时候直接用。(意思就是,这个类我们提前直接初始化完成,就已经占用一个空间了,到时候,我们使用的时候,就不用再去等待其申请空间了一系列事情,直接用,节省了时间,但是在开始的时候就直接加载,如果我们用不到,那么就占用了内存)

实现方式:

class Singleton
{
public:
  static T* GetInstance()
  {
     return &Data;
  }
private:
  static Singleton Data;//设置为静态成员,全局共享,并且在程序运行前初始化加载
  Singleton()//构造函数设置为私有成员。
  {} 
};
  • 构造函数私有化,无法在类外实例化出对象。
  • 成员变量(资源数据)静态化,资源单独一份,运行前初始化,所以初始化过程不用考虑线程问题。
  • 使用对象时,通过类的接口进行接收。

懒汉模型

1.概念:一开始不会初始化资源,等到我们使用的时候再初始化。(意思是,它不像饿汉模式,在程序运行开始之前就初始化对象,而懒汉模型,就是等你用的时候再去创建,这样不占内存,但是有可能会浪费时间)

但是:在懒汉模型中,要注重线程安全问题。
2.实现方式:
①:线程不安全方式:

class Singleton 
{
public:
 static T* GetInstance() 
 {
   if (data == NULL) 
   {
      data = new T();
   }
   return data;
}
private:
 static Singleton* data;
 Singleton()//构造函数设置为私有成员。
 {} 
};

重要的问题就是,当两个线程同时创建的这个类的时候,那么就会出现了两个对象,那么就违反了单例模式的规定了。

②:线程安全方式:

class Singleton()
{
private:
  volatile static Singleton* data;
  static std::mutex _mutex;
  Singleton()//构造函数设置为私有成员。
  {} 
public:
  volatile static Singleton* Getlnstance()
  {
     if(data == NULL)
     {
        _mutex.lock();
        if(data == NULL)
        {
           data* = new Singlent();
        }
        _mutex.unlock();
     }
     return data;
  }
};

其中:

  • 构造函数私有化。
  • 定义静态指针成员访问。(为了在用的时候申请加载)
  • 在访问接口的时候加锁,保护资源初始化的安全。
  • 在加锁之外二次加锁,提高运行效率。(防止当这个对象已经存在了,本来直接返回,中途还要遇到一次加锁解锁操作的时间浪费)
  • 加volatile关键字,防止编译器过度优化,所以使用其修饰成员变量。(例如,第一次给data为NULL,那么编译器过度优化后,他会认为data一直都是NULL,那么就会每次都会创建一个对象,那么就出问题了)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值