C++_线程池代码看C++类-模板-标准库

发布时间 2023-12-04 18:20:46作者: 辰令

C++线程池

线程池的组成部分:
    线程池管理器(ThreadPoolManager):用于创建并管理线程池
    工作线程(WorkThread): 线程池中线程
    任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
    任务队列:用于存放没有处理的任务。提供一种缓冲机制。
    	
    通过新建一个线程池类,以类来管理资源
        3个公有成员函数与5个私有成员
    
    构造函数接受一个size_t类型的数,表示连接数
    enqueue表示线程池部分中的任务管道,是一个模板函数
https://github.com/progschj/ThreadPool/blob/master/ThreadPool.h 	

C++标准库

 C++ 三个主要方面: 类,模板,标准库
   C++面向对象技术,模板(泛型编程),内存管理
C语言中有三座大山:指针、递归、数据结构。而数据结构有3种必须掌握:Vector、链表、二叉树
容器
 C++ 11标准中加入了unordered系列的容器。
   unordered_map记录元素的hash值,根据hash值判断元素是否相同。
   unordered_map 容器中	 存储时是根据key的hash值判断元素是否相同,即unordered_map内部元素是无序的 
  map相当于java中的TreeMap,unordered_map相当于HashMap 
    结构体用map 重载<运算符,结构体用unordered_map 重载==运算符。
unordered_map模板
unordered_map的迭代器 是一个指针,指向这个元素,通过迭代器来取得它的值	

成员函数: begin  end  size empty   
   emplace  构造及插入一个元素 
   emplace_hint 按提示构造及插入一个元素 
   insert    插入元素
   emplace() 或者 emplace_hint() 方法,它们完成“向容器中添加新键值对”的效率,要比 insert() 方法高 

模板

模板是基于用户为模板参数提供的参数在编译时生成普通类型或函数的构造
 调用函数模板,编译器私底下会 根据传过来的变量创建对应的函数,将它具体化。——这就是通过编译生成的模板函数。
  C++中的模板可以分为两种类型:函数模板和类模板
      函数模板使用一个或多个类型参数作为函数参数,从而定义了一组可重用的函数代码
      
      类模板使用一个或多个类型参数作为类成员的类型,从而定义了一组可重用的类代码
 
使用省略号运算符 (...) 定义采用任意数量的零个或多个类型参数的模板
 template<typename... Arguments> class vtclass;	
	 尖括号<>中,typename和class的作用都一样,都是用作来申明后面的参数是一个虚拟的数据参数类型
     参数均为默认值的模板时,请使用空尖括号		

vector

template <class T, class Allocator = allocator<T>> class vector;

template <class... Args>
pair<iterator, bool> emplace ( Args&&... args );
 输入: 其中,参数 args 表示可直接向该方法传递创建新键值对所需要的 2 个元素的值,其中第一个元素将作为键值对的键,另一个作为键值对的值
 当 emplace() 成功添加新键值对时,返回的迭代器指向新添加的键值对,bool 值为 True;
     当 emplace() 添加新键值对失败时,说明容器中本就包含一个键相等的键值对,
	 此时返回的迭代器指向的就是容器中键相同的这个键值对,bool 值为 False。
 输出:该方法的返回值为 pair 类型值,其包含一个迭代器和一个 bool 类型值

 说明:empalce系列函数通过直接构造对象的方式避免内存拷贝和移动
  调用emplace时,则是将参数传递给元素类型的构造函数,emplace成员使用这些参数在容器管理的内存空间中直接构造元素,没有拷贝操作。
  使用 emplace() 或 emplace_hint() 插入键值对的过程是,直接在 map 容器中的指定位置构造该键值对
   
    emplace_back 如果类或者结构体中没有提供构造函数,那么就不能使用emplace系列函数进行替换
   但是,若key原本就已经存在,则insert只需完成键的对比就可以直接返回了,
       而emplace将必须原地构造一个新的对象才能开始对比,使用emplace将需要额外的构造开销。
   有emplace_front、emplace_back。分别对应容器的
   原有操作insert、push_front、push_back。
   将元素插入到一个指定的位置、将元素插入到容器头部、将元素插入到容器尾部。 
    insert():
        调用构造函数
        调用移动构造函数
        调用移动构造函数
    emplace():
        调用构造函数

函数类型

1.函数返回值类型都是在首位,例如:int GetType();
  C++11开始引入了尾置返回类型,将函数返回值类型放置在函数尾部(如果函数声明与实现写在一起,则放置在函数体之前),
  使用->符号隔开,并将首位的返回值使用auto关键字替代			
	这种类型一般用于返回类型比较复杂的函数用于简化函数定义(比如数组指针)或者某些特殊的结
	  auto enqueue(F&& f, Args&&... args) -> std::future<typename std::result_of<F(Args...)>::type>; 
	  //利用尾置限定符  std future用来获取异步任务的结果
  运用于lambda表达式:[] (int a, int b) -> int { return a + b; }	  
2.在C++中,有时我们需要获取函数或可调用对象的返回值类型,以便进行后续的操作
         C++11引入了std::result_of和std::result_of_t(C++14),这两个模板可以方便地获取函数或可调用对象的返回值类型。
 而在C++17中,废弃了std::result_of而引入了更好用的 std::invoke_result和std::invoke_result_t

3.C++11中提供了std::bind。bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的
    template< class F, class... Args >
    /*unspecified*/ bind( F&& f, Args&&... args );
     
    template< class R, class F, class... Args >
    /*unspecified*/ bind( F&& f, Args&&... args );
函数对象,比如函数对象、函数指针、函数引用、成员函数或者数据成员函数。
 args 为函数的入参列表,使用命名空间占位符std::placeholders::_1(第1个参数),std::placeholders::_2(第2个参数)等标志参数。

C++默认成员函数

六个默认成员函数:默认成员函数:用户没有显式实现,编译器会生成的成员函数
 没有自定义的移动构造函数、移动赋值运算符、拷贝构造函数,拷贝赋值运算符或者析构函数时
  编译器会自动生成一个非explicit的inline public隐式移动构造函数T::T(T&&)
    构造函数和析构函数 
        构造函数 - 自动调用
        析构函数 - 自动调用
    拷贝构造函数
    运算符重载
    取地址及const
	取地址操作符重载
说明	
    拷贝构造函数和赋值运算符的区别:
             拷贝构造函数:用一个对象初始化创建另一个对象
             赋值运算符重载:两个已经创建的对象,一个赋值给另一个	
    
6个成员函数    
     默认构造函数
     		默认构造函数指不需要参数就能初始化的构造函数。包含无参和所有参数有默认值两种类型的构造函数。
     析构函数
       		
     拷贝构造函数 const Foo& foo
     		复制构造函数指使用该类的对象作为参数的构造函数。可以有其他参数,但必须提供默认值。
     复制赋值运算符 Foo& operator=(const Foo& foo)
     		重载等号=,将该类的对象赋值给已定义对象。
     移动构造函数  Foo&& foo
     		C++11新增,该类的右值对象为参数的构造函数,其余同复制构造函数。
     移动赋值运算符 Foo& operator=(Foo&& foo)
     		同复制赋值运算符,唯一不同是参数为右值
 英文
    拷贝构造函数(copy constructor)、
    拷贝赋值运算符(copy assignment operator)、
    移动构造函数(move constructor):
         一个右值引用(rvalue reference)创建新的对象,而无需进行深拷贝(deep copy)
    	 构造函数后面写 noexcept
    移动赋值运算符(move assignment operator)

内联函数

 C语言给出的办法是——宏: 在预处理阶段就会将函数与程序中对应的语句进行替换,进而优化了多次调用函数所开辟的函数栈帧。
 C++中替代宏的方法
      由于宏有这三个缺点,C++中给出了替代宏的方法:
      (1)常量定义换用const enum    const enum是C语言中就有的
      (2)短小函数定义换用内联函数 使用inline关键字修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,因此没有函数调用建立栈帧的开销,进而提升程序运行的效率。
   内联函数的声明和定义分离会导致链接错误,所以使用内联函数就直接在该源文件中定义
 类的声明和实现分开
类内声明
外联是相对于内联说的,只有类才有内联外联函数。类的成员函数可以分为内联函数和外联函数	 
类内定义:将函数的函数体定义在类内  
     类内定义与内联函数的关系:类内定义就是默认为inline内联函数
类外定义:
    类外定义就是函数体在类外面,分为同文件类外定义和分文件类外定义  

inline 是对编译器的建议	
外联函数是声明在类体内,定义在类体外的成员函数。外联函数的函数体在类的实现部分		

使用

 #include "ThreadPool.h"
  ThreadPool pool(4); 
     pool.enqueue([i] 

参考

详细介绍C++STL:unordered_map  https://www.cnblogs.com/langyao/p/8823092.html