提问人:Tharani B 提问时间:1/12/2023 最后编辑:Tharani B 更新时间:1/12/2023 访问量:290
ThreadPool、函数局部变量和 Thread 本地存储
ThreadPool, Function local variables and Thread local storage
问:
在线程池中,线程被重用以避免线程的创建和破坏。当线程池重用线程时,它不会清除线程本地存储中的数据。因此,当方法检查线程本地存储时,它找到的值是早期使用线程池线程时遗留的。
函数局部变量是函数的局部变量,而不是线程的局部变量。但是当我使用 boost::asio::thread_pool 创建线程池时,函数内部创建的局部变量的内存共享同一线程的相同内存。
因此,我有几个问题......
- 是存储在线程本地存储中的函数局部变量。是因为我为相同的线程获得了相同的内存吗?
- 对于按值传递的函数参数,同样的问题是什么?
- 在重用线程之前,有没有办法清除线程本地存储?
程序
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/asio/thread_pool.hpp>
#include <BoostThreading/UtilBoost.hpp>
#include <iostream>
boost::mutex mutex;
void my_task(int g)
{
boost::lock_guard<boost::mutex> lock(mutex);
int i=0;
i++;
std::cout<<boost::this_thread::get_id()<<" "<<&i<<" "<<i<<" "<<&g<<" "<<g<<"\n";
SleepMs(30);
}
int main()
{
boost::asio::thread_pool pool(4);
for(int i=0;i<10;i++)
boost::asio::post(pool, boost::bind(my_task,i));
pool.join();
}
第一个地址是线程 id,第二个是在函数中创建的变量 i 的地址,第三个地址是通过传递值传递给my_task的变量 g 的地址。
答:
1赞
sehe
1/12/2023
#1
- 是存储在线程本地存储中的函数局部变量。是因为我为相同的线程获得了相同的内存吗?
函数局部变量位于堆栈上。
堆栈实际上始终(隐式)线程本地。这是 CPU 设计的直接结果。
唯一的例外可能是在上下文切换库(例如实现堆栈协程或纤程)时。
阅读这个绝对很棒的答案,了解堆栈分配和堆栈重用:局部变量的内存可以在其范围之外访问吗?
- 对于按值传递的函数参数,同样的问题是什么?
同样的答案。
- 在重用线程之前,有没有办法清除线程本地存储?
这实际上是一个有趣的问题。它概括为“C++ 中是否有包含具有自动存储持续时间的对象的安全擦除分配器?
不,那不存在。它可以是近似的,但它将涉及将所有基元类型包装成非平凡类型。在任务结束时使用显式函数主动擦除堆栈可能更有效。
上层框架必须保持原样,因为它们可能(并且将)包含正确线程管理所需的信息(例如,如果您使用它,它将包含允许线程中断的结构,线程本地存储的可移植仿真等)boost::thread
boost::thread_specific_ptr
如果您需要这样的东西,请寻找一个围绕“安全擦除”的现有库,因为它非常容易出错。例如,一个朴素的调用可以(并且将)经常被编译器优化掉。memset
评论