parent
1832de1241
commit
c1b1b26d1a
@ -1,130 +0,0 @@
|
||||
#pragma once
|
||||
#include <vector_type>
|
||||
#include <utility>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#ifndef __AQ_USE_THREADEDGC__
|
||||
class GC {
|
||||
private:
|
||||
template<class T>
|
||||
using vector = vector_type<T>;
|
||||
template<class ...T>
|
||||
using tuple = std::tuple<T...>;
|
||||
|
||||
size_t current_size = 0, max_size,
|
||||
interval, forced_clean,
|
||||
forceclean_timer = 0;
|
||||
bool running, alive;
|
||||
// ptr, dealloc, ref, sz
|
||||
vector<tuple<void*, void (*)(void*)>> *q, *q_back;
|
||||
std::thread handle;
|
||||
std::atomic<std::thread::id> lock;
|
||||
// maybe use volatile std::thread::id instead
|
||||
protected:
|
||||
void acquire_lock() {
|
||||
auto this_pid = std::this_thread::get_id();
|
||||
while(lock != this_pid)
|
||||
{
|
||||
while(lock != this_pid && lock != std::thread::id()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(0));
|
||||
}
|
||||
lock = this_pid;
|
||||
}
|
||||
}
|
||||
|
||||
void release_lock(){
|
||||
lock = std::thread::id();
|
||||
}
|
||||
|
||||
void gc()
|
||||
{
|
||||
if (q->size == 0)
|
||||
return;
|
||||
auto t = q;
|
||||
acquire_lock();
|
||||
q = q_back;
|
||||
release_lock();
|
||||
for(const auto& t : *t) {
|
||||
std::get<1>(t)(std::get<0>(t));
|
||||
}
|
||||
t->clear();
|
||||
q_back = t;
|
||||
running = false;
|
||||
current_size = 0;
|
||||
}
|
||||
|
||||
|
||||
void daemon() {
|
||||
using namespace std::chrono;
|
||||
|
||||
while (alive) {
|
||||
if (running) {
|
||||
if (current_size > max_size ||
|
||||
forceclean_timer > forced_clean)
|
||||
{
|
||||
gc();
|
||||
forceclean_timer = 0;
|
||||
}
|
||||
std::this_thread::sleep_for(microseconds(interval));
|
||||
forceclean_timer += interval;
|
||||
}
|
||||
else {
|
||||
std::this_thread::sleep_for(10ms);
|
||||
forceclean_timer += 10000;
|
||||
}
|
||||
}
|
||||
}
|
||||
void start_deamon() {
|
||||
q = new vector<tuple<void*, void (*)(void*)>>();
|
||||
q_back = new vector<tuple<void*, void (*)(void*)>>();
|
||||
lock = thread::id();
|
||||
alive = true;
|
||||
handle = std::thread(&daemon);
|
||||
}
|
||||
|
||||
void terminate_daemon() {
|
||||
running = false;
|
||||
alive = false;
|
||||
delete q;
|
||||
delete q_back;
|
||||
using namespace std::chrono;
|
||||
|
||||
if (handle.joinable()) {
|
||||
std::this_thread::sleep_for(microseconds(1000 + std::max(static_cast<size_t>(10000), interval)));
|
||||
handle.join();
|
||||
}
|
||||
}
|
||||
public:
|
||||
void reg(void* v, uint32_t sz = 1,
|
||||
void(*f)(void*) = [](void* v) {free (v); }
|
||||
) {
|
||||
acquire_lock();
|
||||
current_size += sz;
|
||||
q.push_back({ v, f });
|
||||
running = true;
|
||||
release_lock()
|
||||
}
|
||||
|
||||
GC(
|
||||
uint32_t max_size = 0xfffffff, uint32_t interval = 10000,
|
||||
uint32_t forced_clean = 1000000 //one seconds
|
||||
) : max_size(max_size), interval(interval), forced_clean(forced_clean){
|
||||
start_deamon();
|
||||
} // 256 MB
|
||||
|
||||
~GC(){
|
||||
terminate_daemon();
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
class GC {
|
||||
public:
|
||||
GC(uint32_t) = default;
|
||||
void reg(
|
||||
void* v, uint32_t = 0,
|
||||
void(*f)(void*) = [](void* v) {free (v); }
|
||||
) const { f(v); }
|
||||
}
|
||||
#endif
|
Loading…
Reference in new issue