(6 探讨六) 使用库里全局函数 ref 。通过以上咱们已知道:子线程中的函数执行,即使函数形参是引用,也引用不到主线程中的实参变量。子线程中函数对形参的修改,也不会影响主线程中实参变量的值。但如果一定要在子线程中的函数里修改主线程中对应的值。就要避免传递引用和变量本身,而改为使用全局函数 std::ref() 和指向变量的指针。测试如下:
原因就要参考 reference_wrapper 模板类的源码:
因为借助 ref ,可以直接使用对象的引用,避免使用对象指针,还是更方便的。
(7 探讨七) 创建线程时传递的函数是如何在全局函数 invoke 里被调用的。传递给线程要执行的函数,可以是普通函数,可调用对象,类的成员函数(又有静态和非静态之分),对象的成员指针指向的对象的成员函数。其与 invoke 中 elseif 分支的对应关系如下:
这个图在上篇中出现过,但当时注释不甚精准,再修正补充一下。
时间来到了第二天,看了王老师的课以后,又对上图中的 elseif 分支,多明白了一些。补充到下图里:
上图中出现了 reference_wrapper 对象的 get 函数,其定义如下:
其成员函数也说明, reference_wrapper 类型的变量完全可以当做对象的引用来使用。相应的测试如下:
(8 探讨八)创建线程的第一个参数,可以是普通函数,或者可调用对象,还可以是对对象的引用:非 &obj_A 格式,这是取对象的地址,而是 std :: ref ( obj_A ) 的返回值 reference_wrapper 对象,该对象可以当成是对可调用对象的引用。测试如下:
因为对 全局 invoke 函数的分支执行的打印还没有删。出现了 invoke 函数的两次调用,这是为什么呢,而且为什么 reference_wrapper 对象也可以作为创建线程的第一个参数呢?图解如下:
(9 探讨九) join 函数的放置位置,应在主线程中靠后的位置,因为会阻塞主线程,测试如下:
看源码对 join 函数的定义:
作为反例,移动下 join 的位置,则子线程陷入了死循环,如下图,正是因为如此,才第一次发现了 join 的位置放置,也要注意,也是有大学问的:
谢谢