#include #include #include #include struct WorkerArgs { float x0, x1; float y0, y1; unsigned int width; unsigned int height; int maxIterations; int *output; int threadId; int numThreads; }; extern void mandelbrot_serial(float x0, float y0, float x1, float y1, int width, int height, int start_row, int num_rows, int max_iterations, int *output); // // worker_thread_start -- // // Thread entrypoint. void worker_thread_start(WorkerArgs *const args) { // TODO FOR PP STUDENTS: Implement the body of the worker // thread here. Each thread could make a call to mandelbrot_serial() // to compute a part of the output image. For example, in a // program that uses two threads, thread 0 could compute the top // half of the image and thread 1 could compute the bottom half. // Of course, you can copy mandelbrot_serial() to this file and // modify it to pursue a better performance. printf("Hello world from thread %d\n", args->threadId); } // // mandelbrot_thread -- // // Multi-threaded implementation of mandelbrot set image generation. // Threads of execution are created by spawning std::threads. void mandelbrot_thread(int num_threads, float x0, float y0, float x1, float y1, int width, int height, int max_iterations, int *output) { static constexpr int max_threads = 32; if (num_threads > max_threads) { fprintf(stderr, "Error: Max allowed threads is %d\n", max_threads); exit(1); } // Creates thread objects that do not yet represent a thread. std::array workers; std::array args = {}; for (int i = 0; i < num_threads; i++) { // TODO FOR PP STUDENTS: You may or may not wish to modify // the per-thread arguments here. The code below copies the // same arguments for each thread args[i].x0 = x0; args[i].y0 = y0; args[i].x1 = x1; args[i].y1 = y1; args[i].width = width; args[i].height = height; args[i].maxIterations = max_iterations; args[i].numThreads = num_threads; args[i].output = output; args[i].threadId = i; } // Spawn the worker threads. Note that only numThreads-1 std::threads // are created and the main application thread is used as a worker // as well. for (int i = 1; i < num_threads; i++) { workers[i] = std::thread(worker_thread_start, &args[i]); } worker_thread_start(&args[0]); // join worker threads for (int i = 1; i < num_threads; i++) { workers[i].join(); } }