首页 > 其他分享 >多线程之OMP

多线程之OMP

时间:2023-08-02 10:48:43浏览次数:54  
标签:std include cout OMP omp pragma using 多线程

记录在学习games101的时候碰到的多线程知识

以下所有结果均在Ubuntu 22.04.2 LTS操作系统下使用g++ 11.3.0运行
image
所有的问题来自下面这段代码,这是games101 的第七次作业的一部分,需要使用多线程加速Path Tracing

		int use_critical =0;
        float pocess=0;
        float scale = tan(deg2rad(scene.fov * 0.5));
        float imageAspectRatio = scene.width / (float)scene.height;
        Vector3f eye_pos(278, 273, -800);
        std::cout << "SPP: " << spp << "\n";
        int cpuNum= sysconf(_SC_NPROCESSORS_CONF);
		std::cout<<"Cpu Num :" <<cpuNum<<std::endl;
        omp_set_num_threads(cpuNum);
        //int handle[cpuNum];
        float minY=0.0f,maxY=0.0f;
        int m = 0;
        int hxw=scene.width*scene.height;
        #pragma omp parallel for shared(pocess)
            for (uint32_t p = 0; p < hxw; ++p)
            {
                int i = p % scene.height;
                int j = p / scene.height;
                // 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[p] += scene.castRay(Ray(eye_pos, dir), 0) / spp;
                }
                pocess++;
                #pragma omp critical 
                    UpdateProgress(pocess / (float)(scene.height * scene.width));
            }
             //Threadlist[i]=std::thread(RenderWithMultiThread,minY,maxY);
            minY=maxY+1.0f;
        UpdateProgress(1.f);
        // save framebuffer to file
        string filename ="binaryWithMultiThread";
        filename +=std::to_string(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now()-start).count())+".ppm";
        FILE* fp = fopen(filename.c_str(), "wb");
        (void)fprintf(fp, "P6\n%d %d\n255\n", scene.width, scene.height);
        for (auto i = 0; i < scene.height * scene.width; ++i) {
            static unsigned char color[3];
            color[0] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].x), 0.6f));
            color[1] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].y), 0.6f));
            color[2] = (unsigned char)(255 * std::pow(clamp(0, 1, framebuffer[i].z), 0.6f));
            fwrite(color, 1, 3, fp);
        }
        fclose(fp);

OMP如何跑起来?

在linux操作系统下,使用g++ test.cpp -fopenmp -o test编译。先测试一下这段代码,以确保你会使用g++进行编译:

#include <iostream>
using std::cout;
using std::endl;
int main()
{
    #pragma omp parallel
    cout<<"hello,openmp!\n";
    cout.flush();
}

编译运行:

g++ test.cpp -fopenmp -o test
./test

你可能得到的是不同的结果,但应该也只是数量上的不同,这取决于你电脑的核心数目。
image
我们正式开始

#pragma omp parallel

这个预处理用于开启多线程,上面已经实验过了,这里不进行过多的解释。接下来让我们控制线程的数量:

线程数量

#pragma omp parallel num_threads(2)

#include <iostream>
using std::cout;
using std::endl;
int main()
{
    #pragma omp parallel num_threads(2)
    cout<<"hello,openmp!\n";
    cout.flush();
}

运行这段代码,你可以看到hello 只剩下了两个。

APIomp_set_num_threads()

首先添加头文件#include"omp.h",然后使用APIomp_set_num_threads()

#include <iostream>
#include"omp.h"
using std::cout;
using std::endl;
int main()
{
    omp_set_num_threads(2);
    #pragma omp parallel
    cout<<"hello,openmp!\n";
    cout.flush();
}

可以得到和上面一样的结果。

环境变量OMP_NUM_THREADS

在编译之前,加上这句修改环境变量的指令,就可以实现运行前,编译后修改线程数量了。

export OMP_NUM_THREADS=2

在此之前,把你的测试代码修改为这样:并重新编译,然后你便可以控制你的线程数量了

#include <iostream>
#include"omp.h"
using std::cout;
using std::endl;
int main()
{
    #pragma omp parallel
    cout<<"hello,openmp!\n";
    cout.flush();
}

image

加速for循环

#omp pragma parallel for

#include <iostream>
#include <chrono>
#include "omp.h"
using std::cout;
using std::endl;
int main()
{
    long long sum = 0;
    auto start = std::chrono::system_clock::now();
    #pragma omp parallel reduction(+:sum)
    #pragma omp for 
    for (int i = 3; i < 500000; i++)
    {
        bool flag = true;
        for (int j = 2; j < i; j++)
        {
            if (i % j == 0)
            {
                flag = false;
                break;
            }
        }
        if (flag)
            sum += i;
    }
    auto end = std::chrono::system_clock::now();
    cout<<std::chrono::duration_cast<std::chrono::microseconds>(end-start).count()<<endl;
    cout << "sum: " << sum << endl;
    cout.flush();
}

我随便写了一段,来对比多线程与单线程的差距:图中第一个是16线程跑出来的\(2530ms\),也就是2.5s,第二个是单线程,\(14147ms\),也就是14.1s接近7倍的差距,没有16倍的速度是很正常的,我这个测试程序写的非常随意。只是单纯的说明加速情况而已。当然,答案是一样的。

image

上面代码中还出现了reduction(+:sum)这样的指令,这是我们接下来要讲的东西。

规约操作

使用reduction()来制定规约操作

reduction(<operator>: <variable list>)

这个指令可以让所有线程的结果通过规约合并在一起,比如上面程序的+:sum,就是每个线程分别计算sum,再累加在一起。

本文参考

大佬的博客

标签:std,include,cout,OMP,omp,pragma,using,多线程
From: https://www.cnblogs.com/zhywyt/p/17599676.html

相关文章

  • compact:这是用于压缩文件和目录的Windows命令。它允许你在磁盘上节省空间,通过将文件和
    compact命令选项外,Windows操作系统中还有一些其他的compact命令选项,如下所示:compact/c:该选项用于强制压缩文件,即使它们已经被压缩过。它会覆盖现有的压缩设置。compact/i:此选项用于仅压缩文件中的空闲空间。它可以用于在磁盘上释放未使用的空间。compact/f:这个选项用于强制......
  • Python使用 - 多线程
    常见术语及用法 基本使用#定义线程类classMyThread(threading.Thread):def__init__(self):super(MyThread,self).__init__()#或threading.Thread.__init__(self)defrun(self)->None:tid=threading.currentThread().ident......
  • 什么是gil锁、python的垃圾回收机制是什么样的?解释为什么计算密集型用多进程,io密集型
    目录1什么是gil锁-全局解释器锁:gil锁的作用是什么?为什么要有gil锁?2python的垃圾回收机制是什么样的?-引用计数-标记清除-分代回收3解释为什么计算密集型用多进程,io密集型用多线程计算密集型任务:I/O密集型任务:总结:1什么是gil锁-全局解释器锁:它的本质就是一个大的互斥锁,它......
  • centos7安装docker-compose
    首先确保系统已经安装上了docker1、下载tar包并上传至服务器解压下载地址:https://package-all-1257309290.cos.ap-beijing.myqcloud.com/docker_compose_install.tar.gztarzxfdocker_compose_install.tar.gz2、安装docker-compose解压后得到一个docker_compose_installcd......
  • Best Heavy Duty Truck Diagnostic Software Of 2023 Completed List
    Diagnostictoolsareessentialintheautomotiveindustryforidentifyingandresolvingissueswithvehicles.Thesetoolsprovidetechnicianswiththenecessaryinformationtodiagnoseandrepairproblemsefficiently.Inthisarticle,wewillexplorethe......
  • A Compiler Writing Journey
     DoctorWkt/acwj:ACompilerWritingJourney(github.com) ACompilerWritingJourneyInthisGithubrepository,I'mdocumentingmyjourneytowriteaself-compilingcompilerforasubsetoftheClanguage.I'malsowritingoutthedetailssot......
  • 发电站乐队歌词全中译 / The Comprehensive Chinese Translation of Kraftwerk Lyrics
    发电站乐队歌词全中译/TheComprehensiveChineseTranslationofKraftwerkLyrics发电站所有英文版录音室专辑的歌词中文翻译。《TheMix》和《Minimum-Maximum》为重混(remix)或演唱会专辑,故《Expo2000》和《PlanetofVisions》单列,其它单曲的歌词并入其它专辑中,作为某首歌......
  • c++多线程同步
    死锁问题1单核实时可抢占的系统中,优先级不同的三个线程A/B/C,A>B>C当C先获得时间片开始执行,并获得锁A因为高优先级,被唤醒并中断C,但没有得到锁,而阻塞B获得执行机会,由于优先级高于C,B会一直执行,让AC系统无法取得任何进展std::stack<T>stack;std::mutexmutex;voidpush(c......
  • java-多线程并发,CompletableFuture
    //无返回值@OverridepublicvoidexecCreateYmDetDataSubTask(YmDetCreateWorkerDtoymDetCreateWorkerDto){List<Long>sendIdList=ymDetCreateWorkerDto.getSendIdList();List<List<Long>>subLists=Lists.partition(sendIdList,1......
  • Gym104128L Proposition Composition
    很好口胡却不好写。把边分成链边和额外边首先想到分类讨论,显然不能只删额外边,所以有两类情况,删一链边和两链边。如果删一链边,这一链边要么完全没被额外边覆盖,然后其他任选一条;要么被覆盖一次,额外边选覆盖它的边。用线段树简单维护即可。现在难的是删两链边,且这两条链边都至少......