OpenMP Fractal Generator - PullRequest
       36

OpenMP Fractal Generator

0 голосов
/ 13 декабря 2018

Я пытался создать вариант openMP набора julia, но я не могу создать связное изображение при запуске более одного потока, я пытался решить то, что похоже на состояние гонки, но не могунайти ошибку.Неправильный вывод выглядит как требуемый вывод вместе с «линиями сканирования» по всей картине.

Я также приложил код, если он недостаточно ясен.

#include <iostream>
#include <math.h>
#include <fstream>
#include <sstream>
#include <omp.h>
#include <QtWidgets>
#include <QElapsedTimer>
using namespace std;



double newReal(int x, int imageWidth){
    return 1.5*(x - imageWidth / 2)/(0.5 * imageWidth);
}

double newImaginary(int y, int imageHeight){
    return (y - imageHeight / 2) / (0.5 * imageHeight);
}

int julia(double& newReal, double& newImaginary, double& oldReal, double& oldImaginary, double cRe, double cIm,int maxIterations){
    int i;
    for(i = 0; i < maxIterations; i++){
      oldReal = newReal;
      oldImaginary = newImaginary;
      newReal = oldReal * oldReal - oldImaginary * oldImaginary + cRe;
      newImaginary = 2 * oldReal * oldImaginary + cIm;
      if((newReal * newReal + newImaginary * newImaginary) > 4) break;
    }
    return i;
}
int main(int argc, char *argv[])
{
    int fnum=atoi(argv[1]);
    int numThr=atoi(argv[2]);
//    int imageHeight=atoi(argv[3]);
//    int imageWidth=atoi(arg[4]);
//    int maxIterations=atoi(argv[5]);
//    double cRe=atof(argv[3]);
//    double cIm=atof(argv[4]);
    //double cRe, cIm;
    int imageWidth=10000, imageHeight=10000, maxIterations=3000;
    double newRe, newIm, oldRe, oldIm,cRe,cIm;
    cRe = -0.7;
    cIm = 0.27015;
    string fname;
    QElapsedTimer time;
    QImage img(imageHeight, imageWidth, QImage::Format_RGB888);//Qimagetesting
    img.fill(QColor(Qt::black).rgb());//Qimagetesting
    time.start();
    int i,x,y;
    int r, gr, b;
#pragma omp parallel for shared(imageHeight,imageWidth,newRe,newIm) private(x,y,i) num_threads(3)
        for(y = 0; y < imageHeight; y++)
        {
            for(x = 0; x < imageWidth; x++)
            {
                newRe = newReal(x,imageWidth);
                newIm = newImaginary(y,imageHeight);
                i= julia(newRe, newIm, oldRe, oldIm, cRe, cIm, maxIterations);

                r = (3*i % 256);
                gr = (2*(int)sqrt(i) % 256);
                b = (i % 256);
                img.setPixel(x, y, qRgb(r, gr, b));
             }
        }

    //stringstream s;
    //s << fnum;
    //fname= "julia" + s.str();
    //fname+=".png";
    //img.save(fname.c_str(),"PNG", 100);
    img.save("julia.png","PNG", 100);
    cout<< "Finished"<<endl;
    cout<<time.elapsed()/1000.00<<" seconds"<<endl;
}

1 Ответ

0 голосов
/ 20 декабря 2018

Как указано в комментариях, у вас есть две основные проблемы:

  • newRe и newIm являются общими, но не должны быть
  • r, grи b доступ не указан (по умолчанию, я думаю)
  • Есть одновременные вызовы QImage::setPixel

Чтобы исправить это, не стесняйтесь сделатьЦикл omp for, вложенный в блок omp parallel.

Объявление частной переменной непосредственно перед циклом for:

Для предотвращения одновременных вызовов QImage::setPixel, , так как эта функцияне является потокобезопасным , вы можете поместить его в критическую область с помощью #pragma omp critical.


int main(int argc, char *argv[])
{
    int imageWidth=1000, imageHeight=1000, maxIterations=3000;

    double cRe = -0.7;
    double cIm = 0.27015;

    QElapsedTimer time;
    QImage img(imageHeight, imageWidth, QImage::Format_RGB888);//Qimagetesting
    img.fill(Qt::black);
    time.start();

    #pragma omp parallel
    {
        /* all folowing values will be private */
        int i,x,y;
        int r, gr, b;
        double newRe, newIm, oldRe, oldIm;

        #pragma omp for
        for(y = 0; y < imageHeight; y++)
        {            
            for(x = 0; x < imageWidth; x++)
            {
                newRe = newReal(x,imageWidth);
                newIm = newImaginary(y,imageHeight);
                i= julia(newRe, newIm, oldRe, oldIm, cRe, cIm, maxIterations);

                r = (3*i % 256);
                gr = (2*(int)sqrtf(i) % 256);
                b = (i % 256);

                #pragma omp critical
                    img.setPixel(x, y, qRgb(r, gr, b));
             }
        }
    }

    img.save("julia.png","PNG", 100);

    cout<<time.elapsed()/1000.00<<" seconds"<<endl;

    return 0;
}

Чтобы пойти дальше, вы можете сэкономить некоторое время процессора, заменив ::setPixel на ::scanLine:

    #pragma omp for
    for(y = 0; y < imageHeight; y++)
    {                        
        uchar *line = img.scanLine(y);
        for(x = 0; x < imageWidth; x++)
        {
            newRe = newReal(x,imageWidth);
            newIm = newImaginary(y,imageHeight);
            i= julia(newRe, newIm, oldRe, oldIm, cRe, cIm, maxIterations);

            r = (3*i % 256);
            gr = (2*(int)sqrtf(i) % 256);
            b = (i % 256);

            *line++ = r;
            *line++ = gr;
            *line++ = b;
         }
    }

РЕДАКТИРОВАТЬ:

Поскольку набор джулии, кажется, имеет центральную симметрию около точки (0,0), вы можете выполнить только половину исчисления:

int half_heigt = imageHeight / 2;
#pragma omp for

// compute only for first half of image
for(y = 0; y < half_heigt; y++)
{            
    for(x = 0; x < imageWidth; x++)
    {
        newRe = newReal(x,imageWidth);
        newIm = newImaginary(y,imageHeight);
        i= julia(newRe, newIm, oldRe, oldIm, cRe, cIm, maxIterations);

        r = (3*i % 256);
        gr = (2*(int)sqrtf(i) % 256);
        b = (i % 256);

        #pragma omp critical
        {
            // set the point  
            img.setPixel(x, y, qRgb(r, gr, b));

            // set the symetric point
            img.setPixel(imageWidth-1-x, imageHeight-1-y, qRgb(r, gr, b));
        }
     }
}
...