|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <functional>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <stack>
|
|
|
|
#include <queue>
|
|
|
|
#include <memory>
|
|
|
|
#include <vector>
|
|
|
|
#include <thread>
|
|
|
|
#include <mutex>
|
|
|
|
#include <chrono>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
using call_frame_target = void*call_frame_target(void*, void*);
|
|
|
|
|
|
|
|
struct packaged_call_frame {
|
|
|
|
void* arguments;
|
|
|
|
}
|
|
|
|
|
|
|
|
class package_of_work {
|
|
|
|
public:
|
|
|
|
|
|
|
|
package_of_work(int kind, call_frame_target target, void* scope_) :
|
|
|
|
kind_id(kind), work_factor(1), target_function(target), scope(scope_), finalized(false)
|
|
|
|
{
|
|
|
|
queue = std::queue()
|
|
|
|
}
|
|
|
|
|
|
|
|
int kind_id;
|
|
|
|
float work_factor;
|
|
|
|
std::queue<packaged_call_frame> queue;
|
|
|
|
|
|
|
|
call_frame_target target_function;
|
|
|
|
void* scope;
|
|
|
|
|
|
|
|
bool finalized;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct call_frame {
|
|
|
|
void* arguments;
|
|
|
|
void* scope;
|
|
|
|
call_frame_target target_function;
|
|
|
|
int id;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct call_result {
|
|
|
|
int nothing;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class GlobalThreadPool {
|
|
|
|
public:
|
|
|
|
GlobalThreadPool();
|
|
|
|
|
|
|
|
int create_package(void* scope, call_frame_target target_function);
|
|
|
|
void submit_to_package(int kind_id, void* arguments);
|
|
|
|
struct call_result join_package(int kind_id);
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unordered_map<int, package_of_work> m_work_packages;
|
|
|
|
std::stack<package_of_work> m_work_package_stack;
|
|
|
|
std::mutex m_work_packages_lock;
|
|
|
|
|
|
|
|
std::queue<struct call_frame> m_calls;
|
|
|
|
std::mutex m_calls_lock;
|
|
|
|
|
|
|
|
std::unordered_map<int, call_result> m_results;
|
|
|
|
std::mutex m_results_lock;
|
|
|
|
|
|
|
|
volatile int m_last_id;
|
|
|
|
std::mutex m_id_lock;
|
|
|
|
|
|
|
|
std::vector<std::thread> m_trheads;
|
|
|
|
|
|
|
|
void thread_worker();
|
|
|
|
}
|
|
|
|
|
|
|
|
void GlobalThreadPool::thread_worker() {
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
package_of_work* current = NULL;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
if (m_work_package_stack.size > 0) {
|
|
|
|
// grab a reference to the first queue
|
|
|
|
current = m_work_package_stack.top;
|
|
|
|
}
|
|
|
|
|
|
|
|
// if not finalized, try again
|
|
|
|
if (!current->finalized && current->queue.size == 0) {
|
|
|
|
std::this_thread::sleep_for(100ms);
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int GlobalThreadPool::create_package(void* scope, call_frame_target target_function)
|
|
|
|
{
|
|
|
|
this->id_lock.lock()
|
|
|
|
int kind_id = this->last_id++;
|
|
|
|
this->id_lock.unlock()
|
|
|
|
|
|
|
|
this->work_packages_lock.lock()
|
|
|
|
auto package = package_of_work(kind_id, target_function, scope);
|
|
|
|
this->work_packages[kind_id] = package;
|
|
|
|
this->work_package_stack.push(package);
|
|
|
|
this->work_packages_lock.unlock()
|
|
|
|
|
|
|
|
return kind_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
|