threadpool_w_triangulation/triangulation.cpp

282 lines
7.2 KiB
C++

#include <thread>
#include <chrono>
#include <ctime>
#include <cstdlib>
#include <iostream>
#include <mutex>
#include <vector>
#include <queue>
#include <atomic>
#include <condition_variable>
#include <cmath>
#include <map>
#include <random>
#include "libpoly.h"
//############################################################ GLOBALS
std::condition_variable can_pop;
std::condition_variable can_push;
std::atomic_uint32_t active_producents;
std::atomic_uint32_t active_consuments;
std::atomic_bool tasks_incoming;
std::ostream& os = std::cout;
std::mutex os_l;
//############################# MODIFY HERE
constexpr unsigned NUM_PRODUCENTS = 1;
constexpr unsigned NUM_WORKERS = 3;
//############################################################ COMMON STRUCTURES
struct Temp_Task: public std::enable_shared_from_this< Temp_Task > {
LP_Polygon p;
double minimal_triangulation;
Temp_Task(LP_Polygon&& _p): p(_p){}
};
using Temp_Task_p = std::shared_ptr< Temp_Task >;
class Task {
private:
Temp_Task_p task;
double triangulate(LP_Polygon* p);
double triangulate();
double triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m);
public:
Task(): task(nullptr){};
Task(const Task&) = delete;
Task(Task&& t): task(t.task){
t.task.reset();
}
Task(Temp_Task_p&& tp): task(tp){}
void solve_stupid(){
task->minimal_triangulation = triangulate(&(task->p));
}
Temp_Task_p unwrap(){ // TODO: vymyslet jinak, zaručit po tomto kroku selfdestruct
return std::move(task);
}
double const solution(){ return task->minimal_triangulation; }
};
class Queue{
std::queue<Task> q;
std::mutex q_l;
const size_t MAX_LENGHT = 100'000;
public:
void push(Task&& t){
std::unique_lock<std::mutex> pushlock(q_l);
can_push.wait(pushlock, [this](){ return (q.size() < MAX_LENGHT); });
q.push(std::move(t));
pushlock.unlock();
can_pop.notify_one();
}
Task pop(){
std::unique_lock<std::mutex> poplock(q_l);
can_pop.wait(poplock, [this](){ return !is_empty(); });
Task t(std::move(q.front()));
q.pop();
poplock.unlock();
can_push.notify_one();
return t;
}
bool is_empty( ){
return q.empty();
}
};
using task_queue_ptr = std::shared_ptr<Queue>;
//############################################################ PRODUCE THREAD
class Producent{
private:
task_queue_ptr task_queue;
public:
Producent(task_queue_ptr tq): task_queue(tq){ active_producents++; }
Producent(const Producent&) = delete;
~Producent(){ active_producents--; }
Task get_task(){
//LP_Task_p tp = pickup_task();
//#########################3TEMP_PART:
std::vector< LP_Point > points;
srand(static_cast<unsigned int>(std::chrono::system_clock::now().time_since_epoch().count()));
int num_of_points = (rand()%10) + 1;
for(int i = 0; i < num_of_points; i++){
LP_Point p;
p.x = rand()%199 +1;
p.y = rand()%199 +1;
points.push_back(p);
}
LP_Polygon p(std::move(points));
Temp_Task_p tp = std::make_shared<Temp_Task>(std::move( p ));
return Task(std::move(tp));
}
void fill_queue(){
while(tasks_incoming){
//Task t = get_task();
task_queue->push(get_task());
}
}
};
void produce_thread(task_queue_ptr task_queue){
Producent p(task_queue);
p.fill_queue();
}
//############################################################ WORKER THREAD
class Consument {
private:
task_queue_ptr task_queue;
public:
Consument(task_queue_ptr tq): task_queue(tq){ active_consuments++; }
Consument(const Consument&) = delete;
~Consument() { active_consuments--; }
Task get_task(){ // might be redundant
return task_queue->pop();
}
void work(){
while(active_producents || ! task_queue->is_empty()){
Task t = get_task();
t.solve_stupid();
//submit_task(std::move(t.unwrap()));
os_l.lock();
os << t.solution() << std::endl;
os_l.unlock();
}
}
};
void consume_thread(task_queue_ptr task_queue){
Consument c(task_queue);
c.work();
}
//############################################################ TRIANGULATION
struct Line{
LP_Point a;
LP_Point b;
double length;
Line() = delete;
Line(LP_Point _a, LP_Point _b): a(_a), b(_b){
LP_Point vec_ba;
vec_ba.x = b.x - a.x;
vec_ba.y = b.y - a.y;
length = sqrt(vec_ba.x*vec_ba.x + vec_ba.y*vec_ba.y);
}
Line(Line& l): a(l.a), b(l.b), length(l.length){}
};
double Task::triangulate(LP_Polygon* p){
size_t poly_size = p->points.size();
if(poly_size == 3) return 0.;
double triangulation;
double min_triangulation = INFINITY;
for (size_t point_idx = 0; point_idx < poly_size; point_idx++){
Line cut(p->points.at( (point_idx - 1) % poly_size ),
p->points.at( (point_idx + 1) % poly_size ));
std::vector<LP_Point> smaller_poly;
for(size_t i = 0; i < poly_size; i++){
if(i != point_idx) smaller_poly.push_back(p->points.at(i));
}
LP_Polygon s_p(std::move(smaller_poly));
triangulation = triangulate(&s_p) + cut.length;
if(triangulation < min_triangulation) min_triangulation = triangulation;
}
return min_triangulation;
}
//############################### dynamic something
//use std::map to store triangulations of polygons
//KEY CREATION:
// take relative positions of points in polygon, add them as vectors and do something with the amount of them
// maybe num * vx + num^2 * vy
double Task::triangulate(){
std::map<int, double> m;
std::vector<bool> poly_key;
return triangulate_subpolys(poly_key, &m);
}
int vec_to_int(std::vector<bool>* vec){
int res = 0;
for (size_t i = 0; i < vec->size(); i++){
res += vec->at(i) * 2^i;
}
return res;
}
double Task::triangulate_subpolys(std::vector<bool> poly_key, std::map<int, double>* m){
// convert p to int
// try to find in map
// success -> return mapped value
// failure -> compute triangulation
// save value in map
// return found value
// COMPUTE TRIANGULATION
// create polygon poly from p
// use stupid triangulation but create poly_key instead of small_poly
return 0.;
}
//############################################################ MAIN
int main(){
active_producents = active_consuments = 0;
tasks_incoming = true;
task_queue_ptr queue_ptr = std::make_shared<Queue>();
std::vector<std::thread> threads;
for(unsigned int i = 0; i < NUM_PRODUCENTS; i++){
threads.emplace_back(produce_thread, queue_ptr);
}
for(unsigned int i = 0; i < NUM_WORKERS; i++){
threads.emplace_back(consume_thread, queue_ptr);
}
std::this_thread::sleep_for(std::chrono::milliseconds(5));
tasks_incoming = false;
for(auto& t : threads){
t.join();
os_l.lock();
os << "joined" << std::endl;
os_l.unlock();
}
//test();
}