Games101,作业7(多线程提速)

多线程

多线程的相关信息可根据我的另一个blog查看。

多线程处理提速方式

将像素width*height分隔为多份,每一份交给一个线程处理。

分隔方式有:

  • 网格分隔(代码中使用了这种分隔方式)
  • 条形分隔(每一列 或 每一行 为一个线程,更利于编程)

线程代码

  • 输入为线程需要操作的像素区间。x∈[min_x,max_x],y∈[min_y,max_y]
  • 对于网状分隔方式,m横线移动时,数值是连续的,故只需要在纵向移动时初始化m的值。
  • std::lock_guard<std::mutex> lock(mutex_ins);锁管理器

锁管理器:
多个线程访问外部同一个变量并对该变量进行修改时,可能会因为混乱的修改代码的先后顺序导致修改的变量不符合预期。这时候需要锁管理器,使得每一个线程中的修改代码执行完毕后再去执行其他线程的内容。

对于该线程框架:

  • framebuffer[m]为每一个像素的值,而每一个线程有独立计算的像素,相互之间互不影响,故不需要考虑代码运行的先后顺序。
  • process为外部变量,是每一个线程都要修改的公共变量,因为其修改代码只有一句++process(在汇编中只是一条指令,process++也只是两条指令),因此不使用锁管理器可能也不会造成数据混乱。(建议使用锁管理器)
  • UpdateProgress((float)process / scene.height / y_block);为更新进程函数,因为进程信息的显示不能混乱,如果混乱就会…看下面的图。
auto castRayMultiThread = [&](int min_x,int min_y,int max_x,int max_y) {
        for (uint32_t j = min_y; j < max_y; ++j) {
            int m = j  *scene.width + min_x;
            for (uint32_t i = min_x; i < max_x; ++i) {
                // generate primary ray direction
                float x = (2 * (i + 0.5) / (float)scene.width - 1) *
                    imageAspectRatio * scale;
                float y = (1 - 2 * (j + 0.5) / (float)scene.height) * scale;
    
                Vector3f dir = normalize(Vector3f(-x, y, 1));
                for (int k = 0; k < spp; k++) {
                    framebuffer[m] += scene.castRay(Ray(eye_pos, dir), 0) / spp;
                }
                m++;
                
            }
            {
                std::lock_guard<std::mutex> lock(mutex_ins);
                ++process;
                UpdateProgress((float)process / scene.height / y_block);
            }
            
        }
    };

在这里插入图片描述

分隔、启动线程

要确保分隔的线程中像素点不会有重叠,且不会遗漏像素点或越界。

	//分块为5*5个处理单元
    const int x_block = 5;
    const int y_block = 5;
    std::thread th[x_block * y_block];
    //步距计算,步距多加1,保证无论像素有多少,所有像素都可被包含在块中
    int strideX = scene.width / x_block + 1;
    int strideY = scene.height / y_block + 1;

	线程lamada表达式

	// 分块计算光线追踪 
    int id = 0;
    for (int i = 0; i < y_block; i++){//height
        for (int j = 0; j < x_block; j++){//width
            th[id] = std::thread(castRayMultiThread, j* strideX, i* strideY, std::min((j+1)* strideY, scene.width), std::min((i+1) * strideY, scene.height));
            id++;
        }
    }
    for (int i = 0; i < x_block * y_block; i++) th[i].join();
    UpdateProgress(1.f);

提速效果

spp16-----由先前的6分钟提速为30秒左右。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Elsa的迷弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值