来自线程函数内部的线程保护变量
Thread protected variables from inside a threaded function
我为从多线程函数生成像素的软件编写了一个简单的 raytracer 插件。
伪代码是
Scene* scene;
void engine_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
Buffer* line;
my_render_engine(y, scene, buffered_line); // here is where I'm accessing a lot of shared data, incurring into data racing
out = *buffered_line; // here I have just a line of pixels
}
My Scene* 包含许多共享变量(相机、采样器、着色器等),渲染器只需要读取它们。这些是在调用 engine_ 之前生成的。同时访问它们会产生未定义的行为。
我已经获取了一个 thread_pool 模板,试图像这样保护我的线程
void engine\_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
m.lock()
Buffer\* line(width);
auto render_line = \[this\](int y, int x, Buffer\* buffer) {
Scene thread_scene = Scene();
... creating scene ...
}
thread_world.camera_ptr->my_render_engine(y, x, r, thread_scene , buffer_image_ptr);
};
//for (int j = 0; j < height; j++)
m_threadPool.AddTask(render_line, j, x, r, buffer_image_ptr); // running render function for each
//thread safely
m.unlock()
out = *buffered_image; // here I have my entire image
}
这有点管用,或者至少我能够保护我的变量。它在很多方面都非常低效,需要改进,比如生成与我的内核数量恰到好处的场景。
最大的问题是,除非我等待生成整个图像,否则我无法想象我在做什么,这是我做不到的。
engine_ 函数让我在每一行像素生成后立即对其进行可视化,但我必须让它这样做。按原样使用我的线程池显然不起作用,因为我用简单的话覆盖了 engine_。
一个临时的解决方案是每次我 运行 这样的渲染器创建一个全新的场景
void engine_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
Scene* thread_scene; .....creating scene..... Buffer* line(width);
my_render_engine(y, 3dscene, buffered_line); // here is where I'm accessing a lot of shared data, incurring into data racing
out = *buffered_line; // here I have just a line of pixels
}
它与 thread_pool 类似,但它让我可以逐行可视化生成的图像。
问题是没有很好的线程保护。在场景内部,有着色器和 3dsampler,它们在许多 3d 对象(如相机、灯光和几何体)之间共享。
所以这里是我需要帮助的地方:
我 'think' 当我创建我的场景时,其中的变量指针在线程之间共享,当线程同时访问它们时程序崩溃:
class Scene{
Camera* cam;
Sampler* sampler;
Object_list<object*> objs;
Tracer* tracer_ptr;
Shader_list<shader*> shaders
}; // these pointers refer to the same stuff
我的问题是:
->我说得对吗?即使我正在创建场景的多个副本,我也没有保护它们的变量?
-> 如果是这样的话,我怎样才能使这些变量受到保护?希望我不需要复制它们(尤其是 mesh_ptr 非常重。
我会首先选择 std::shared_mutex
用作 read-write mutex
。
当您访问 reading 的共享变量时,您将使用 lock_shared
、unlock_shared
、try_lock_shared
基元 - 并且,显然,您不会写入这些变量!
当您访问它们以 写入 时,您将使用通常的 lock
、unlock
和 try_lock
原语来获得独占访问- 然后,您就可以安全地编写它们了。
如果在那之后你的问题没有得到解决,那么你的代码中可能有其他损坏的东西。
我已经设法通过创建包含每个线程所需数据的映射和 thread::id 来解决问题。数据是 World class,其中包含共享 read-access 数据的指针和非共享数据的副本(希望是线程安全的,但我不完全确定)。
const std::thread::id tID = std::this_thread::get_id();
m_lock.lock();
std::map<const std::thread::id, World*>::iterator thread_it = worlds_map.find(tID);
if (thread_it == worlds_map.end())
{
//creating new scene for thread map
World* thread_world = new World();
thread_world->set_bg_texture(input_texture_ptr);
thread_world->build();
.........
// adding to thread map
worlds_map[tID] = thread_world;
}
thread_it = worlds_map.find(tID);
m_lock.unlock();
thread_it->second->camera_ptr->render_scene(y, x, r, buffer_image_ptr, *thread_it->second);
}```
this way I only need to create an instance for each thread my cpu has and not for each row
我为从多线程函数生成像素的软件编写了一个简单的 raytracer 插件。 伪代码是
Scene* scene;
void engine_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
Buffer* line;
my_render_engine(y, scene, buffered_line); // here is where I'm accessing a lot of shared data, incurring into data racing
out = *buffered_line; // here I have just a line of pixels
}
My Scene* 包含许多共享变量(相机、采样器、着色器等),渲染器只需要读取它们。这些是在调用 engine_ 之前生成的。同时访问它们会产生未定义的行为。
我已经获取了一个 thread_pool 模板,试图像这样保护我的线程
void engine\_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
m.lock()
Buffer\* line(width);
auto render_line = \[this\](int y, int x, Buffer\* buffer) {
Scene thread_scene = Scene();
... creating scene ...
}
thread_world.camera_ptr->my_render_engine(y, x, r, thread_scene , buffer_image_ptr);
};
//for (int j = 0; j < height; j++)
m_threadPool.AddTask(render_line, j, x, r, buffer_image_ptr); // running render function for each
//thread safely
m.unlock()
out = *buffered_image; // here I have my entire image
}
这有点管用,或者至少我能够保护我的变量。它在很多方面都非常低效,需要改进,比如生成与我的内核数量恰到好处的场景。 最大的问题是,除非我等待生成整个图像,否则我无法想象我在做什么,这是我做不到的。 engine_ 函数让我在每一行像素生成后立即对其进行可视化,但我必须让它这样做。按原样使用我的线程池显然不起作用,因为我用简单的话覆盖了 engine_。
一个临时的解决方案是每次我 运行 这样的渲染器创建一个全新的场景
void engine_(int y, int, x, pixel& out){ // this function is threaded for each orizontal line y
Scene* thread_scene; .....creating scene..... Buffer* line(width);
my_render_engine(y, 3dscene, buffered_line); // here is where I'm accessing a lot of shared data, incurring into data racing
out = *buffered_line; // here I have just a line of pixels
}
它与 thread_pool 类似,但它让我可以逐行可视化生成的图像。 问题是没有很好的线程保护。在场景内部,有着色器和 3dsampler,它们在许多 3d 对象(如相机、灯光和几何体)之间共享。
所以这里是我需要帮助的地方:
我 'think' 当我创建我的场景时,其中的变量指针在线程之间共享,当线程同时访问它们时程序崩溃:
class Scene{
Camera* cam;
Sampler* sampler;
Object_list<object*> objs;
Tracer* tracer_ptr;
Shader_list<shader*> shaders
}; // these pointers refer to the same stuff
我的问题是: ->我说得对吗?即使我正在创建场景的多个副本,我也没有保护它们的变量? -> 如果是这样的话,我怎样才能使这些变量受到保护?希望我不需要复制它们(尤其是 mesh_ptr 非常重。
我会首先选择 std::shared_mutex
用作 read-write mutex
。
当您访问 reading 的共享变量时,您将使用 lock_shared
、unlock_shared
、try_lock_shared
基元 - 并且,显然,您不会写入这些变量!
当您访问它们以 写入 时,您将使用通常的 lock
、unlock
和 try_lock
原语来获得独占访问- 然后,您就可以安全地编写它们了。
如果在那之后你的问题没有得到解决,那么你的代码中可能有其他损坏的东西。
我已经设法通过创建包含每个线程所需数据的映射和 thread::id 来解决问题。数据是 World class,其中包含共享 read-access 数据的指针和非共享数据的副本(希望是线程安全的,但我不完全确定)。
const std::thread::id tID = std::this_thread::get_id();
m_lock.lock();
std::map<const std::thread::id, World*>::iterator thread_it = worlds_map.find(tID);
if (thread_it == worlds_map.end())
{
//creating new scene for thread map
World* thread_world = new World();
thread_world->set_bg_texture(input_texture_ptr);
thread_world->build();
.........
// adding to thread map
worlds_map[tID] = thread_world;
}
thread_it = worlds_map.find(tID);
m_lock.unlock();
thread_it->second->camera_ptr->render_scene(y, x, r, buffer_image_ptr, *thread_it->second);
}```
this way I only need to create an instance for each thread my cpu has and not for each row