summaryrefslogtreecommitdiff
path: root/mthread_old
diff options
context:
space:
mode:
authorBrett Weiland <brett_weiland@bpcspace.com>2023-01-23 14:43:30 -0600
committerBrett Weiland <brett_weiland@bpcspace.com>2023-01-23 14:43:30 -0600
commit3b97e627caa6883391bd1e9f3c31172e10bf7404 (patch)
tree534962ac997ec72434f964129d4ba17ad792ce95 /mthread_old
parent61bd7df99d32b8c489383568afc53117ab1fa81f (diff)
finished functions to achieve polymorphism
Diffstat (limited to 'mthread_old')
-rw-r--r--mthread_old269
1 files changed, 269 insertions, 0 deletions
diff --git a/mthread_old b/mthread_old
new file mode 100644
index 0000000..9f7df9f
--- /dev/null
+++ b/mthread_old
@@ -0,0 +1,269 @@
+#include "mthread.hpp"
+#include <iostream>
+#include <complex>
+#include <unistd.h>
+#include <thread>
+#include <chrono>
+#include <cmath>
+#include <algorithm>
+#include <atomic>
+using namespace std;
+
+mthread::mthread(
+ unsigned int x_mn, unsigned int x_mx, complex<double> c_min, complex<double> c_max,
+ unsigned int inf_cutoff, unsigned int max_iter, png& image, double *g_vmap, unsigned int *g_histogram,
+ mthread **worker_list, unsigned int id, unsigned int jobs, atomic<uint32_t>& progress)
+ : x_min_orig(x_mn), x_max_orig(x_mx),
+ c_min(c_min), c_max(c_max),
+ inf_cutoff(inf_cutoff), max_iter(max_iter), image(image), id(id), worker_cnt(jobs), progress(progress){
+
+ workers = worker_list;
+ x_min = x_mn;
+ x_max = x_mx;
+ y_min = 0;
+ y_max = image.height();
+ vmap = g_vmap;
+ histogram = g_histogram;
+ step = (c_max - c_min) / complex<double>(image.height(), image.width());
+ my_thread = NULL;
+
+status.status_lock.lock();
+ status.searching = false;
+ status.share_finished = false;
+ status.div_syn = false;
+ status.div_error = false;
+ status.status_lock.unlock();
+}
+
+void mthread::dispatch() {
+ if((my_thread) && (my_thread->joinable())) delete my_thread;
+ my_thread = new thread([this] {render();});
+}
+
+
+mthread::~mthread() {
+ if((my_thread) && (my_thread->joinable())) {
+ my_thread->join();
+ delete my_thread;
+ }
+}
+
+
+void mthread::join() {
+ if((my_thread) && (my_thread->joinable())) my_thread->join();
+}
+
+//TODO make final
+//looks for work
+void mthread::find_work() {
+}
+
+//makes sure no one is asking for work from us
+void mthread::check_work_request() {
+ unique_lock<mutex> ack;
+ unique_lock<mutex> syn_ack;
+
+ status.status_lock.lock();
+ status.row_load = y_max - on_y;
+ //check if anyone's asking us to divide
+ if(status.div_syn) {
+ status.div_error = status.row_load <= min_lines;
+ if(status.div_error) {
+ status.ack_lk.unlock();
+ status.msg_notify.notify_all();
+ }
+ else {
+ syn_ack = unique_lock<mutex>(status.syn_ack_lk);
+ status.ack_lk.unlock();
+ status.msg_notify.notify_all();
+ status.msg_notify.wait(syn_ack);
+ status.row_load = y_max - on_y;
+ syn_ack.unlock();
+ //new x/y min/max is ajusted by other thread, we can continue as normal.
+ }
+ }
+ status.status_lock.unlock();
+}
+
+//renders area
+void mthread::render_area() { //TODO rename
+}
+
+//alternates states of finding work work and rendering
+void mthread::run() {
+ for(;;) {
+ }
+}
+
+
+//TODO move syncronization to another function for extensibility
+void mthread::render() {
+ uint32_t image_width = image.width();
+ unsigned int iter;
+ unsigned int worker, workers_finished;
+ uint32_t loads[worker_cnt];
+ double pixel_value;
+ complex<double> c, a;
+ struct mthread_status *peer_status;
+ struct mthread_divinfo divinfo;
+
+ unique_lock<mutex> ack;
+ unique_lock<mutex> syn_ack;
+
+
+ status.status_lock.lock();
+ status.searching = false;
+ status.share_finished = false;
+ status.div_syn = false;
+ status.div_error = false;
+ status.status_lock.unlock();
+
+
+ y_min = 0;
+ y_max = image.height();
+
+
+
+ for(;;) {
+ //thread is actively rendering
+ for(on_y = y_min; on_y < y_max; on_y++) {
+ progress++;
+ check_work_request();
+ /**
+ status.status_lock.lock();
+ status.row_load = y_max - on_y;
+ //check if anyone's asking us to divide
+ if(status.div_syn) {
+ status.div_error = status.row_load <= min_lines;
+ if(status.div_error) {
+ status.ack_lk.unlock();
+ status.msg_notify.notify_all();
+ }
+ else {
+ syn_ack = unique_lock<mutex>(status.syn_ack_lk);
+ status.ack_lk.unlock();
+ status.msg_notify.notify_all();
+ status.msg_notify.wait(syn_ack);
+ status.row_load = y_max - on_y;
+ syn_ack.unlock();
+ //new x/y min/max is ajusted by other thread, we can continue as normal.
+ }
+ }
+ status.status_lock.unlock();
+ **/
+
+ for(on_x = x_min; on_x < x_max; on_x++) {
+ c = (step * complex<double>(on_x,on_y)) + c_min;
+ a = 0;
+ for(iter = 0; iter < max_iter; iter++) {
+ if(abs(a) >= inf_cutoff) break;
+ a = a*a + c;
+ }
+ if(iter >= max_iter) {
+ iter = 0;
+ vmap[(on_y * image_width) + on_x] = 0;
+ }
+ else {
+ pixel_value = (iter + 1) - (log((log(pow(abs(a), 2.0)) / 2.0) / log(2.0)));
+ vmap[(on_y * image_width) + on_x] = pixel_value;
+ histogram[(int)pixel_value]++;
+ }
+ }
+ }
+
+
+ //thread is now searching for work
+
+ /** 2022 comment:
+ * this state should have been moved to a seperate function to allow rendering methods to differ
+ * from inherited mthreads without needing to reimpliment searching **/
+ status.status_lock.lock();
+ status.searching = true;
+ status.share_finished = true;
+ status.status_lock.unlock();
+
+ //first we look over all workers to see which are canidates to ask for work
+ while(status.searching) {
+ workers_finished = 0;
+ //TODO do we really need this whole for loop?
+ for(worker = 0; worker < worker_cnt; worker++) {
+ //lock other worker so we can request from them
+ peer_status = &workers[worker]->status;
+ peer_status->status_lock.lock();
+
+ //if they're done, we remember that to see if we exit
+ if((peer_status->share_finished) && (worker != id)) {
+ workers_finished++;
+ }
+ //if they're us, currently looking for work,
+ //or don't have enough work for us to complete, then skip
+
+ if((worker == id) ||
+ (peer_status->searching) || (peer_status->div_syn) || (peer_status->row_load < min_lines)) {
+ loads[worker] = 0;
+ peer_status->status_lock.unlock();
+ continue;
+ }
+ //finally, if they're valid, write them down
+ loads[worker] = peer_status->row_load;
+ peer_status->status_lock.unlock();
+ }
+ //exit if all workers are finished
+ if(workers_finished >= worker_cnt - 1) {
+ return;
+ }
+ //then we look over and pick our canidates
+ for(;;) {
+ //find the worker who has the biggest workload
+ worker = distance(loads, max_element(loads, &loads[worker_cnt]));
+ if(!loads[worker]) break; //we have found a worker; distance is 0
+ peer_status = &workers[worker]->status;
+ peer_status->status_lock.lock();
+ //check to see if canidate is valid.
+ //TODO do we really need to check the first time?
+ if((peer_status->searching) || (peer_status->div_syn) || (peer_status->row_load < min_lines)) {
+ loads[worker] = 0;
+ peer_status->status_lock.unlock();
+ continue;
+ }
+ ack = unique_lock<mutex>(peer_status->ack_lk);
+ peer_status->div_syn = true;
+ peer_status->status_lock.unlock();
+ peer_status->msg_notify.wait(ack);
+ ack.unlock();
+ if(peer_status->div_error) {
+ loads[worker] = 0;
+ peer_status->status_lock.lock();
+ peer_status->div_error = false;
+ peer_status->div_syn = false;
+ peer_status->status_lock.unlock();
+ continue;
+ }
+
+ divinfo = workers[worker]->divide();
+ peer_status->syn_ack_lk.unlock();
+ peer_status->msg_notify.notify_all();
+ y_min = divinfo.y_min;
+ y_max = divinfo.y_max;
+ x_min = divinfo.x_min;
+ x_max = divinfo.x_max;
+ status.status_lock.lock();
+ status.searching = false;
+ status.status_lock.unlock();
+ break;
+ }
+ }
+ }
+}
+
+struct mthread_divinfo mthread::divide() {
+ struct mthread_divinfo ret;
+ ret.x_min = x_min;
+ ret.x_max = x_max;
+ ret.y_min = ((y_max - on_y) / 2) + on_y;
+ ret.y_max = y_max;
+ y_min = on_y;
+ y_max = ret.y_min;
+ status.div_syn = false;
+ return ret;
+}