#include <chrono> 
#include <cstdint> 
#include <cstdlib> 
#include <complex> 
#include <fstream> 
#include <iostream> 
#include <thread> 
#include <mutex> 
#include <condition_variable> 
 
using std::chrono::duration_cast; 
using std::chrono::milliseconds; 
using std::chrono::seconds; 
using std::complex; 
using std::cout; 
using std::endl; 
using std::this_thread::sleep_for; 
using std::ofstream; 
using std::thread; 
using std::mutex; 
using std::condition_variable; 
using std::unique_lock; 
mutex mutex1; 
mutex mutex2; 
std::condition_variable done; 
 
typedef std::chrono::steady_clock the_clock; 
 
 
 
const int WIDTH1 = 960; 
const int HEIGHT1 = 600; 
const int WIDTH2 = 1920; 
const int HEIGHT2 = 1200; 
int finished_threads = 0; 
 
 
const int MAX_ITERATIONS = 500; 
 
 
uint32_t image[HEIGHT2][WIDTH2]; 
 
 
 
struct ThreadArgs { int id; int delay; }; 
void myThreadFunc(ThreadArgs args) 
 
{ 
    for (int i = 0; i < 1; i++) { 
        sleep_for(seconds(args.delay)); 
        cout << args.id; 
    } 
} 
void write_tga(const char *filename) 
{ 
    unique_lock<mutex> lock(mutex2); 
    while (finished_threads < 2) { 
        done.wait(lock); 
    } 
    ofstream outfile(filename, ofstream::binary); 
 
    uint8_t header[18] = { 
        0, // no image ID 
        0, // no colour map 
        2, // uncompressed 24-bit image 
        0, 0, 0, 0, 0, // empty colour map specification 
        0, 0, // X origin 
        0, 0, // Y origin 
        WIDTH2 & 0xFF, (WIDTH2 >> 8) & 0xFF, // width 
        HEIGHT2 & 0xFF, (HEIGHT2 >> 8) & 0xFF, // height 
        24, // bits per pixel 
        0, // image descriptor 
    }; 
    outfile.write((const char *)header, 18); 
 
    for (int y = 0; y < HEIGHT2; ++y) 
    { 
        for (int x = 0; x < WIDTH2; ++x) 
        { 
            uint8_t pixel[3] = { 
                image[y][x] & 0xFF, // blue channel 
                (image[y][x] >> 8) & 0xFF, // green channel 
                (image[y][x] >> 16) & 0xFF, // red channel 
            }; 
            outfile.write((const char *)pixel, 3); 
        } 
    } 
 
    outfile.close(); 
    if (!outfile) 
    { 
 
        cout << "Error writing to " << filename << endl; 
        exit(1); 
    } 
} 
 
 
// Render the Mandelbrot set into the image array. 
// The parameters specify the region on the complex plane to plot. 
void compute_mandelbrot(double left, double right, double top, double bottom) 
 
{ 
    unique_lock<mutex> lock(mutex2); 
 
    for (int y = 0; y < HEIGHT1; ++y) 
    { 
        for (int x = 0; x < WIDTH1; ++x) 
        { 
 
            complex<double> c(left + (x * (right - left) / WIDTH2), 
                top + (y * (bottom - top) / HEIGHT2)); 
 
            // Start off z at (0, 0). 
            complex<double> z(0.0, 0.0); 
 
            // Iterate z = z^2 + c until z moves more than 2 units 
            // away from (0, 0), or we've iterated too many times. 
            int iterations = 0; 
            mutex1.lock(); 
            while (abs(z) < 2.0 && iterations < MAX_ITERATIONS) 
            { 
                z = (z * z) + c; 
 
                ++iterations; 
            } 
            mutex1.unlock(); 
            if (iterations == MAX_ITERATIONS) 
            { 
 
                image[y][x] = 0x000000; // black 
            } 
            else 
            { 
 
                image[y][x] = 0xFFFFFF; // white 
                finished_threads = finished_threads + 1; 
                done.notify_all(); 
            } 
        } 
    } 
} 
void compute_mandelbrot2(double left2, double right2, double top2, double bottom2) 
 
{ 
    unique_lock<mutex> lock(mutex2); 
    //map <int, int> val = map<int, int>(0, MAX_ITERATIONS); 
    //map <int, int> colourval = map<int, int>(0, MAX_ITERATIONS); 
    for (int y = HEIGHT1; y < HEIGHT2; ++y) 
    { 
        for (int x = HEIGHT1; x < WIDTH2; ++x) 
        { 
 
            complex<double> c(left2 + (x * (right2 - left2) / WIDTH2), 
                top2 + (y * (bottom2 - top2) / HEIGHT2)); 
 
            // Start off z at (0, 0). 
            complex<double> z(0.0, 0.0); 
 
            // Iterate z = z^2 + c until z moves more than 2 units 
 
            int iterations = 0; 
            mutex1.lock(); 
            while (abs(z) < 2.0 && iterations < MAX_ITERATIONS) 
            { 
                z = (z * z) + c; 
 
                ++iterations; 
            } 
            mutex1.unlock(); 
            if (iterations == MAX_ITERATIONS) 
            { 
                // z didn't escape from the circle. 
                // This point is in the Mandelbrot set. 
                image[y][x] = 0x000000; // black 
            } 
            else 
            { 
                // z escaped within less than MAX_ITERATIONS 
                // iterations. This point isn't in the set. 
                image[y][x] = 0xFFFFFF; // white 
                finished_threads = finished_threads + 1; 
                done.notify_one(); 
            } 
        } 
    } 
} 
 
 
int main(int argc, char *argv[]) 
{ 
 
    std::thread myThread; 
    std::thread myThread2; 
    std::thread myThread3; 
 
    ThreadArgs args; 
 
    myThread = std::thread(compute_mandelbrot, -2.0, 1.0, 1.125, -1.125); 
    myThread3 = std::thread(compute_mandelbrot2, -2.0, 1.0, 1.125, -1.125); 
    myThread2 = std::thread(write_tga, "output.tga"); 
 
    cout << "Please wait..." << endl; 
 
    // Start timing 
    the_clock::time_point start = the_clock::now(); 
 
 
 
    myThread.join(); 
    myThread3.join(); 
 
 
 
 
    // Stop timing 
    the_clock::time_point end = the_clock::now(); 
 
    // Compute the difference between the two times in milliseconds 
    auto time_taken = duration_cast<milliseconds>(end - start).count(); 
    cout << "Computing the Mandelbrot set took " << time_taken << " ms." << endl; 
 
 
    myThread2.join(); 
 
    return 0; 
} 

上面是代码的多线程版本,它输出的集合版本不正确,其中大多数是黑色的,但有些是正确的,所以我不知道问题是什么: Mandlebrot threaded,但非线程版本输出正确的Mandelbrot设置 Mandelbrot not threaded这个问题可能与我使用多线程的方式有关:我只是不知道自己做错了什么。任何帮助表示赞赏。

请您参考如下方法:

好吧,首先“简单”的事情!您在内部(x)循环的控制语句的compute_mandelbrot2函数中有一个“typo”;这行:

    for (int x = HEIGHT1; x < WIDTH2; ++x) 

应该(当然)应该是:

    for (int x = WIDTH1; x < WIDTH2; ++x) // WIDTH1 not HEIGHT1 

现在来看看更“微妙”的东西。您正在尝试通过将“x”和“y”范围都分成两半来将计算分为两半。这将行不通,因为这将需要四个线程,每个线程处理该图的相关四分之一。为了仅使用两半,两个线程函数 中的'y'范围必须覆盖整个图(但是'x'范围可以适本地分成两部分)。

因此,您的外部('y')循环控制语句应覆盖和两个线程函数的整个范围,并且两者都应如下所示:

for (int y = 0; y < HEIGHT2; ++y) { 
    //... 

我已经对您的代码进行了上述三个更改的测试,并且生成了正确的Mandelbrot设置图像。请随时要求进一步的澄清和/或解释。


评论关闭
IT序号网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!