本文章属于专栏《业界Cpp进阶建议整理》
继续上篇《Effective Modern C++》- 极精简版 30-35条。 本文列出《Effective Modern C++》的36-42条的个人理解的极精简版本。
- Item36、如果有异步的,请指定std::launch::async
- demo代码为:
-
int calculateSum(int a, int b) {sleep(1);return a + b; } int main() {std::future<int> result = std::async(std::launch::async, calculateSum, 10, 20);int sum = result.get();return 0; }
-
- std::launch::async会新启动一个线程执行,频繁地开启和释放线程会影响性能,所以不要在性能要求高的场景频繁使用
- demo代码为:
- Item37、使std::thread所有路径最后都不可结合
- 个人理解:核心是防止thread中的函数没有按照预期推出时,.join会导致线程Hang住,所以用detach。所以少量的异步逻辑用std::launch::async。大量而持续的逻辑(如reactor模式)用std::thread,并在可控范围内join,甚至直到程序退出才join
- Item38、关注不同线程句柄的析构行为
- std::thread必须要程序员管理生命周期,也就是必须join或者detach
- std::future由系统自动释放,并且不阻塞。除非初始化如下面代码,可以理解为std::future对象初始化时,异步函数就已经启动,那么对象析构时,需要等待异步函数执行完
-
std::future<int> result = std::async(std::launch::async, CalculateSum, 10, 20);
-
-
Item39、对于单次通信考虑使用void的futures
- 个人理解:线程间通信使用队列,更容易debug和监控,放弃std::future和std::promise的方式
- Item40、对于并发使用std::atomic,对于特殊内存使用volatile
- 个人理解:并发读写的数据在8个字节(64位机器)之内的使用std::atomic,超出的加锁。放弃在服务代码中使用volatile,它不是为业务代码的多线程服务的,它解决的是中断引入的问题,如果你不写驱动,可以忘记这个只会出现在八股文的关键字。
- Item41、对于移动成本低,且总是被拷贝的可拷贝形参,考虑按值传递
- 个人理解:这是一条模糊而收益不高的建议。我的建议是,内置类型用值传递,自建类型用指针。
- Item42、考虑就地创建而非插入
- 对于vector来说,
- v.push_back("a")调用了两次构造函数,一次构建临时std::string变量、一次在vecotr中构建string对象
- v.emplace_back("a")调用一次构造函数,它使用了完美转发。所以这个需要注意,置入函数可能执行插入函数拒绝的类型转换。
- 在传递的实参数类型需要转换时,emplace_back会有较明显优势
- 个人理解:在c++11以及之后,放弃push_back,使用emplace_back
- 对于vector来说,