@@ -615,3 +615,103 @@ int main(){
615
615
了解其实现,才能更好的使用它。
616
616
617
617
## 实现 `joining_thread`
618
+
619
+ 这个类和 `std::thread` 的区别就是析构函数会自动 `join` 。如果您好好的学习了上一节的内容,阅读了 `std::thread` 的源码,以下内容不会对您构成任何的难度。
620
+
621
+ 我们存储一个 `std::thread` 作为底层数据成员,稍微注意一下构造函数和赋值运算符的实现即可。
622
+
623
+ ```cpp
624
+ class joining_thread {
625
+ std::thread t;
626
+ public:
627
+ joining_thread()noexcept = default;
628
+ template<typename Callable, typename... Args>
629
+ explicit joining_thread(Callable&& func, Args&&...args) :
630
+ t{ std::forward<Callable>(func), std::forward<Args>(args)... } {}
631
+ explicit joining_thread(std::thread t_)noexcept : t{ std::move(t_) } {}
632
+ joining_thread(joining_thread&& other)noexcept : t{ std::move(other.t) } {}
633
+
634
+ joining_thread& operator=(std::thread&& other)noexcept {
635
+ if (joinable()) { // 如果当前有活跃线程,那就先执行完
636
+ join();
637
+ }
638
+ t = std::move(other);
639
+ return *this;
640
+ }
641
+ ~joining_thread() {
642
+ if (joinable()) {
643
+ join();
644
+ }
645
+ }
646
+ void swap(joining_thread& other)noexcept {
647
+ t.swap(other.t);
648
+ }
649
+ std::thread::id get_id()const noexcept {
650
+ return t.get_id();
651
+ }
652
+ bool joinable()const noexcept {
653
+ return t.joinable();
654
+ }
655
+ void join() {
656
+ t.join();
657
+ }
658
+ void detach() {
659
+ t.detach();
660
+ }
661
+ std::thread& data()noexcept {
662
+ return t;
663
+ }
664
+ const std::thread& data()const noexcept {
665
+ return t;
666
+ }
667
+ };
668
+ ```
669
+
670
+ 简单[ 使用] ( https://godbolt.org/z/bM7Ka7be5 ) 一下:
671
+
672
+ ``` cpp
673
+ int main (){
674
+ std::cout << std::this_thread::get_id() << '\n';
675
+ joining_thread thread{[]{
676
+ std::cout << std::this_thread::get_id() << '\n';
677
+ } };
678
+ joining_thread thread2{ std::move(thread) };
679
+ }
680
+ ```
681
+
682
+ ** 使用容器管理线程对象,等待线程执行结束** :
683
+
684
+ ``` cpp
685
+ void do_work (std::size_t id){
686
+ std::cout << id << '\n';
687
+ }
688
+
689
+ int main(){
690
+ std::vector< std::thread > threads;
691
+ for (std::size_t i = 0; i < 10; ++i){
692
+ threads.emplace_back(do_work, i); // 产生线程
693
+ }
694
+ for(auto& thread: threads ){
695
+ thread.join(); // 对每个线程对象调用 join()
696
+ }
697
+ }
698
+ ```
699
+
700
+ > [运行测试](https://godbolt.org/z/rf4h7s63M)。
701
+
702
+ 线程对象代表了线程,管理线程对象也就是管理线程,这个 `vector` 对象管理 10 个线程,保证他们的执行、退出。
703
+
704
+ 使用我们这节实现的 `joining_thread` 则不需要最后的循环 `join()`:
705
+
706
+ ```cpp
707
+ int main(){
708
+ std::vector<joining_thread>threads;
709
+ for (std::size_t i = 0; i < 10; ++i){
710
+ threads.emplace_back(do_work, i);
711
+ }
712
+ }
713
+ ```
714
+
715
+ > [ 运行测试] ( https://godbolt.org/z/8qa95vMz4 ) 。
716
+
717
+ 如果你自己编译了这些代码,相信你注意到了,打印的是乱序的,没什么规律,而且重复运行的结果还不一样,** 这是正常现象** 。多线程执行就是如此,无序且操作可能被打断。使用互斥量可以解决这些问题,这也就是下一章节的内容了。
0 commit comments