前言
在阅读 c++ 实现的 WebServer 源码时,感觉其中线程池实现值得具体分析,此篇博客分析该源码中线程池实现部分。 Vibrancy continued
源码
|
|
源码分析
为什么该线程池所有的实现在 threadpool.h
中完成?
上面源码为线程池的头文件
threadpool.h
,而且该线程池没有对应的threadpool.cpp
实现代码文件,这种在类中实现方法的方式,使得类中方法都是缺省内联的,这样在编译的时候把函数调用的部分直接换成函数代码,而不是进行函数调用,这适用于函数代码少的时候,可以避免调用带来栈空间的消耗,也可以减少一定的调用时间。
explicit
修饰的构造函数如何理解?
通过将构造函数声明为explicit(显式)的方式可以抑制隐式转换。也就是说,explicit构造函数必须显式调用。按默认规定,只用传一个参数的构造函数也定义了一个隐式转换。具体参考:C++ explicit关键字详解
std::make_shared
作用是什么?在什么场景下使用?
如有可能,第一次创建内存资源时,请使用
make_shared
函数创建shared_ptr
。make_shared
异常安全。 它使用同一调用为控制块和资源分配内存,这会减少构造开销。 如果不使用make_shared
,则必须先使用显式new
表达式来创建对象,然后才能将其传递到shared_ptr
构造函数。具体参考:如何:创建和使用 shared_ptr 实例
void detach()
作用?
拆离相关联的线程。 操作系统负责释放终止的线程资源。具体参考:thread类-detach
std::unique_lock
作用及应用场景?
表示可进行实例化以创建管理
mutex
锁定和解锁的对象的模板。uniqie_lock
是个类模板,它的功能跟lock_quard
类似,但比lock_quard
更灵活。在工作中,一般用lock_quard
(推荐使用)就足够了,但在一些特殊的场景下会用到uniqie_lock
。lock_quard
取代了mutex
的lock()
和unlock()
,在lock_quard
的构造函数中上锁,在析构函数中解锁,这点其实在uniqie_lock
中也是一样的。uniqie_lock
在使用上比lock_quard
灵活,但代价就是效率会低一点,并且内存占用量也会相对高一些。具体参考:unique_lock详解 和 unique_lock 类
std::mutex
作用及应用场景?
Mutex
又称互斥量,C++ 11中与Mutex
相关的类(包括锁类型)和函数都声明在<mutex>
头文件中,所以如果你需要使用std::mutex
,就必须包含<mutex>
头文件。std::mutex
是C++11 中最基本的互斥量,std::mutex
对象提供了独占所有权的特性——即不支持递归地对std::mutex
对象上锁,而std::recursive_lock
则可以递归地对互斥量对象上锁。具体参考:C++11 并发指南三(std::mutex 详解)
std::move
与 std::forward
作用及应用场景?
std::forward
比std::move
逻辑略复杂,std::move
是无条件把参数转换为右值,而std::forward
在特定情况下才会这样做:仅当参数是用右值初始化时,才会把它转换为右值。它的意义是使外面的函数调用选择接受右值的版本,实际的移动工作是由外面的函数进行的;使用std::forward来转发参数一般被称为完美转发 (也叫精确传递)。具体参考:C++ 理解std::forward完美转发。这里,使用std::move
将pool->tasks.front()
装换为右值,从而使得std::function
类型的task调用function& operator= (function&& rhs);
构造函数,避免资源重复申请创建。详细讨论参考:知乎std::move回答