网站平台开发报价表怎么做2024年重大政治时事汇总
一:概述
在多线程编程中,如果一个线程需要访问外部作用域的变量,就必须保证这个变量在 线程结束之前依然有效,否则可能会出现 悬空指针(dangling pointer) 的问题,导致 未定义行为。
二:如何解决?
使用 joining_thread
(类似 std::thread
,但会在析构时自动 join()
,且不能 detach()
)可以避免这种问题,因为:
- 线程的生命周期受到管理:不会意外地
detach()
导致资源泄漏。 - 作用域内对象的生命周期受控:确保线程所访问的对象在其执行期间是有效的。
三:代码示例
#include <iostream>
#include <thread>
#include <memory>void f(int* p) {*p = 99;
}int glob = 33;void some_fct(int* p) {int x = 77;std::thread t0(f, &x); // ✅ OK:x 在作用域内std::thread t1(f, p); // ✅ OK:p 是外部传入的std::thread t2(f, &glob); // ✅ OK:glob 是全局变量auto q = std::make_unique<int>(99);std::thread t3(f, q.get()); // ❌ 错误!q 是局部变量,t3 可能在 q 析构后访问无效地址t0.join();t1.join();t2.join();t3.join();
}
以上 t3(f, q.get());
可能会导致 悬空指针,因为 q
在 some_fct()
结束时会被销毁,而 t3
可能仍然在运行,这样 f()
就可能访问已释放的内存,导致 未定义行为。
解决办法:使用 joining_thread
(概念类似 std::thread
,但会在析构时自动 join()
,确保线程不会在变量生命周期之外运行)
#include <iostream>
#include <thread>
#include <memory>class joining_thread {std::thread t;
public:template <typename... Args>explicit joining_thread(Args&&... args) : t(std::forward<Args>(args)...) {}~joining_thread() {if (t.joinable()) {t.join();}}joining_thread(const joining_thread&) = delete;joining_thread& operator=(const joining_thread&) = delete;
};void f(int* p) {*p = 99;
}int glob = 33;void some_fct(int* p) {int x = 77;joining_thread t0(f, &x); // ✅ OK:x 在作用域内joining_thread t1(f, p); // ✅ OK:p 是外部传入的joining_thread t2(f, &glob); // ✅ OK:glob 是全局变量auto q = std::make_unique<int>(99);joining_thread t3(f, q.get()); // ✅ OK:q 仍然在作用域内// 这里不需要手动 join(),析构时会自动 join()
}