Skip to content

Commit a12ffbf

Browse files
committed
完成 实现 joining_thread 的内容
1 parent 59ec90a commit a12ffbf

File tree

1 file changed

+100
-0
lines changed

1 file changed

+100
-0
lines changed

md/02使用thread.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,103 @@ int main(){
615615
了解其实现,才能更好的使用它。
616616
617617
## 实现 `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

Comments
 (0)