#include #include #include #include #include #include #include #include #include #include #include #include #include enum Error { SUCCESS, BAD_ARGUMENT, BAD_FILE }; using Point = std::complex; // Um ponto no plano using Resolution = std::array; // Resolucao x (largura), y (altura) // Classe para representar uma imagem. // Cada pixel e o numero de iteracoes para detectar |z_n| > 2 class Image { std::vector _values; size_t _nrows, _ncols; public: Image(size_t nrows = 0, size_t ncols = 0) : _values(nrows * ncols), _nrows(nrows), _ncols(ncols) {} void resize(size_t nrows, size_t ncols) { _values.resize(nrows * ncols); _nrows = nrows; _ncols = ncols; } size_t num_rows() const { return _nrows; } size_t num_cols() const { return _ncols; } // Operador de funcao e usado para indexacao (linha, coluna). uint8_t &operator()(size_t i, size_t j) { return _values[i * _ncols + j]; } uint8_t const &operator()(size_t i, size_t j) const { return _values[i * _ncols + j]; } }; // Information for next task (starting row). class TaskInfo { size_t current_row{0}; size_t num_rows; size_t task_size; std::mutex mutex; public: TaskInfo(size_t num_rows, size_t task_size) : num_rows(num_rows), task_size(task_size) {} std::tuple get_slice() { std::lock_guard lock(mutex); auto start = current_row; auto finish = current_row + task_size; if (finish > num_rows) { finish = num_rows; } current_row = finish; return {start, finish}; } }; // // Prototipos de alguma funcoes usadas pelo main. // // Escrita de imagem em stream. std::ostream &operator<<(std::ostream &os, Image const &image); // Leitura de argumentos de linha de comando. // Retorna tupla (n. tratablhadores, canto esquerdo inferior, canto direito // superior, resolucao). std::tuple read_args(int argc, char *argv[]); // Cada trabalhador sincroniza o acesso a proxima faixa de linhas // atraves do metodo get_slice (usando um mutex) da estrutura TaskInfo void worker(Point lower_left, Point upper_right, Resolution resolution, TaskInfo &info, Image &image); // // Codigo principal. // int main(int argc, char *argv[]) { size_t constexpr TASK_SIZE = 10; // 10 rows per task auto [n_workers, lower_left, upper_right, resolution, filename] = read_args(argc, argv); Image image(resolution[1], resolution[0]); auto t_start = std::chrono::high_resolution_clock::now(); TaskInfo info{resolution[1], TASK_SIZE}; std::vector threads; for (int t = 0; t < n_workers; ++t) { threads.emplace_back(worker, lower_left, upper_right, resolution, std::ref(info), std::ref(image)); } for (auto &thd : threads) { thd.join(); } auto t_finish = std::chrono::high_resolution_clock::now(); std::cout << "The computation took " << (t_finish - t_start).count() / 1e9 << " seconds.\n"; std::ofstream output(filename); if (!output.is_open()) { std::cerr << "Could not open output file.\n"; return BAD_FILE; } output << image; if (!output.good()) { std::cerr << "Error writing to file.\n"; return BAD_FILE; } return SUCCESS; } std::ostream &operator<<(std::ostream &os, Image const &image) { for (size_t i = 0; i < image.num_rows(); ++i) { for (size_t j = 0; j < image.num_cols(); ++j) { os << static_cast(image(i, j)) << " "; } os << std::endl; } return os; } std::tuple read_args(int argc, char *argv[]) { if (argc < 9) { std::cerr << "usage: " << argv[0] << " " << " " << " " << " \n"; std::exit(BAD_ARGUMENT); } double ar = std::stod(argv[1]); double ai = std::stod(argv[2]); double br = std::stod(argv[3]); double bi = std::stod(argv[4]); if (ar >= br || ai >= bi) { std::cerr << "Position of region delimiting points is wrong.\n"; std::exit(BAD_ARGUMENT); } Point lower_left(ar, ai), upper_right(br, bi); size_t inx = std::stoul(argv[5]); size_t iny = std::stoul(argv[6]); if (inx < 1 || iny < 1) { std::cerr << "Image resolution is wrong.\n"; std::exit(BAD_ARGUMENT); } auto resolution = Resolution{inx, iny}; auto n_workers = std::stoi(argv[8]); if (n_workers <= 0) { std::cerr << "Number of workers must be positive.\n"; std::exit(BAD_ARGUMENT); } return {n_workers, lower_left, upper_right, resolution, argv[7]}; } uint8_t mandel(Point c, uint8_t iter_max = 127) { uint8_t iter{0}; Point z{c}; while (iter < iter_max && abs(z) <= 2.0) { ++iter; z = z * z + c; } return iter; } void worker(Point lower_left, Point upper_right, Resolution resolution, TaskInfo &info, Image &image) { double hx = (upper_right.real() - lower_left.real()) / resolution[0]; double hy = (upper_right.imag() - lower_left.imag()) / resolution[1]; auto [start_row, finish_row] = info.get_slice(); while (start_row < finish_row) { for (size_t row = start_row; row < finish_row; ++row) { auto y = lower_left.imag() + row * hy + hy / 2; for (size_t col = 0; col < resolution[0]; ++col) { auto x = lower_left.real() + col * hx + hx / 2; image(row, col) = mandel(Point{x, y}); } } std::tie(start_row, finish_row) = info.get_slice(); } }