Skip to content
Snippets Groups Projects
Commit 19eee0cf authored by Recolic Keghart's avatar Recolic Keghart
Browse files

[DO NOT BUILD] save my work

parent 8e06e40e
No related branches found
No related tags found
No related merge requests found
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <numeric>
#include <rlib/class_decorator.hpp> #include <rlib/class_decorator.hpp>
...@@ -11,31 +12,47 @@ namespace rlib { ...@@ -11,31 +12,47 @@ namespace rlib {
class easy_condition_variable : rlib::noncopyable { class easy_condition_variable : rlib::noncopyable {
public: public:
easy_condition_variable() easy_condition_variable()
: stdcv(), stdcv_mutex(), notify_count(0) {} : stdcv(), stdcv_mutex(), notify_count(0), notify_all_mark(false) {}
void notify_one() { void notify_one() {
++notify_count;
stdcv.notify_one(); stdcv.notify_one();
} }
void notify_all() { void notify_all() {
notify_all_mark = true;
stdcv.notify_all(); stdcv.notify_all();
} }
const std::function<bool()> determine_wait_cond = [this]{
if(notify_all_mark)
return true;
while(true) {
auto val = notify_count.load();
if(val <= 0)
return false;
if(notify_count.compare_exchange_strong(val, val-1))
return true;
}
};
void wait() { void wait() {
notify_all_mark = false;
std::unique_lock<std::mutex> lk(stdcv_mutex); std::unique_lock<std::mutex> lk(stdcv_mutex);
stdcv.wait(lk, [this]{return notify_count.load() > 0;}); stdcv.wait(lk, determine_wait_cond);
lk.unlock(); lk.unlock();
} }
template< class Rep, class Period > template< class Rep, class Period >
bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) { bool wait_for(const std::chrono::duration<Rep, Period>& rel_time) {
notify_all_mark = false;
std::unique_lock<std::mutex> lk(stdcv_mutex); std::unique_lock<std::mutex> lk(stdcv_mutex);
bool ret = stdcv.wait_for(lk, rel_time, [this]{return notify_count.load() > 0;}); bool ret = stdcv.wait_for(lk, rel_time, determine_wait_cond);
lk.unlock(); lk.unlock();
return ret; return ret;
} }
template< class Clock, class Duration > template< class Clock, class Duration >
bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) { bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time) {
notify_all_mark = false;
std::unique_lock<std::mutex> lk(stdcv_mutex); std::unique_lock<std::mutex> lk(stdcv_mutex);
bool ret = stdcv.wait_until(lk, timeout_time, [this]{return notify_count.load() > 0;}); bool ret = stdcv.wait_until(lk, timeout_time, determine_wait_cond);
lk.unlock(); lk.unlock();
return ret; return ret;
} }
...@@ -43,6 +60,7 @@ namespace rlib { ...@@ -43,6 +60,7 @@ namespace rlib {
std::condition_variable stdcv; std::condition_variable stdcv;
std::mutex stdcv_mutex; std::mutex stdcv_mutex;
std::atomic<int> notify_count; std::atomic<int> notify_count;
std::atomic<bool> notify_all_mark;
}; };
} // namespace rlib } // namespace rlib
......
...@@ -22,48 +22,28 @@ using size_t = unsigned long; ...@@ -22,48 +22,28 @@ using size_t = unsigned long;
namespace rlib { namespace rlib {
struct object_pool_policy_fixed { struct object_pool_policy_fixed {
object_pool_policy_fixed(size_t size) : size(size), used(new std::atomic<size_t>(0)) {} object_pool_policy_fixed(size_t size) : size(size) {}
bool borrow_should_alloc(/*const size_t free_objects, const size_t existing_objects*/) { // TODO: add size argument? size_t objects_should_alloc(const size_t inuse_objects, const size_t avail_objects) const {
// object_pool::borrow calls this funcion.
// If it returns true, object pool will alloc a new object.
// If it returns false, object pool will not alloc a new object.
// If it returns false, THIS FUNCTION MUST HAVE NO SIDE EFFECT!
// If there's no free object, object pool::borrow blocks.
while(true) {
auto used_old = used->load(std::memory_order_acquire);
if(used_old >= size) {
return false;
}
auto used_new = used_old + 1;
if(used->compare_exchange_strong(used_old, used_new, std::memory_order_acq_rel))
break; // success
}
return true;
}
bool release_should_free() {
if(used->load() == 0)
throw std::runtime_error("POLICY detected error: Release object of zero-sized object pool.");
(*used)--;
return false;
}
size_t objects_should_alloc(const size_t inuse_objects, const size_t avail_objects) {
return avail_objects < size ? size - avail_objects : 0; return avail_objects < size ? size - avail_objects : 0;
} }
private: private:
const size_t size; const size_t size;
std::unique_ptr<std::atomic<size_t> > used;
}; };
struct object_pool_policy_dynamic_never_free { struct object_pool_policy_watermarks {
object_pool_policy_dynamic_never_free() : fixed(std::numeric_limits<size_t>::max()) {} // If free/all < alloc_threshold_rate, then alloc more objects.
bool borrow_should_alloc() { object_pool_policy_watermarks(float alloc_threshold_rate = 0.8, size_t min_objects = 8)
return fixed.borrow_should_alloc(); : _alloc_threshold_rate(1.0/alloc_threshold_rate), min_objects(min_objects) {}
} size_t objects_should_alloc(const size_t inuse_objects, const size_t avail_objects) const {
bool release_should_free() { if(avail_objects < min_objects)
return fixed.release_should_free(); return min_objects - avail_objects;
size_t threshold = inuse_objects * _alloc_threshold_rate;
if(threshold > avail_objects)
return threshold - avail_objects;
return 0;
} }
private: private:
object_pool_policy_fixed fixed; const float _alloc_threshold_rate;
const size_t min_objects;
}; };
struct object_pool_policy_dynamic_smart { struct object_pool_policy_dynamic_smart {
...@@ -146,7 +126,7 @@ namespace rlib { ...@@ -146,7 +126,7 @@ namespace rlib {
std::tuple<_bound_construct_args_t ...> _bound_args; std::tuple<_bound_construct_args_t ...> _bound_args;
size_t inuse_objects = 0; size_t inuse_objects = 0;
policy_t policy; const policy_t policy;
std::condition_variable borrow_cv; // use buffer_mutex on notifying alloc event. std::condition_variable borrow_cv; // use buffer_mutex on notifying alloc event.
volatile bool new_obj_ready = false; volatile bool new_obj_ready = false;
void notify_new_object_allocated(size_t how_many) { void notify_new_object_allocated(size_t how_many) {
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
MODULES=string meta trait stdio sio scope_guard MODULES=string meta trait stdio sio scope_guard
XTRA_FLAGS ?= XTRA_FLAGS ?=
CXXFLAGS=-I. -I../.. $(XTRA_FLAGS) CXXFLAGS=-I. -I../.. $(XTRA_FLAGS) -pthread
STD ?= 14 STD ?= 14
FLAGS11=-std=c++11 rlib/libr.a FLAGS11=-std=c++11 rlib/libr.a
FLAGS14=-std=c++14 rlib/libr.a FLAGS14=-std=c++14 rlib/libr.a
...@@ -40,19 +40,12 @@ endif ...@@ -40,19 +40,12 @@ endif
POSTFIX=$(STD)_$(CXX) POSTFIX=$(STD)_$(CXX)
all: string common pool all: string.test common.test pool.test threading.test
common: %.test: src/%.cc
$(CXX) $(CXXFLAGS) src/common.cc $(CXXFLAGS) -o src/common_$(POSTFIX).out @echo Testing $< ...
src/common_$(POSTFIX).out $(CXX) $< $(CXXFLAGS) -o src/$@_$(POSTFIX).out
src/$@_$(POSTFIX).out
string:
$(CXX) $(CXXFLAGS) src/string.cc $(CXXFLAGS) -o src/string_$(POSTFIX).out
src/string_$(POSTFIX).out
pool:
$(CXX) $(CXXFLAGS) src/pool.cc $(CXXFLAGS) -o src/pool_$(POSTFIX).out
src/pool_$(POSTFIX).out
clean: clean:
rm -f src/*.out rm -f src/*.out
......
...@@ -59,13 +59,13 @@ TEST_CASE("fixed object pool") { ...@@ -59,13 +59,13 @@ TEST_CASE("fixed object pool") {
objs.pop_front(); objs.pop_front();
} }
} }
REQUIRE(fixed_pool.size() == 1); REQUIRE(fixed_pool.size() == pool_size);
} }
TEST_CASE("infinite dynamic object pool") { TEST_CASE("infinite dynamic object pool") {
const auto arg1 = string("fuck you 2"); const auto arg1 = string("fuck you 2");
rlib::object_pool<rlib::object_pool_policy_dynamic_never_free, pooled_obj2_t, decltype(arg1)> rlib::object_pool<rlib::object_pool_policy_watermarks, pooled_obj2_t, decltype(arg1)>
inf_pool(rlib::object_pool_policy_dynamic_never_free(), arg1); inf_pool(rlib::object_pool_policy_watermarks(), arg1);
auto res = inf_pool.try_borrow_one(); auto res = inf_pool.try_borrow_one();
REQUIRE(res != nullptr); REQUIRE(res != nullptr);
...@@ -90,8 +90,6 @@ TEST_CASE("infinite dynamic object pool") { ...@@ -90,8 +90,6 @@ TEST_CASE("infinite dynamic object pool") {
} }
// "Leak" one object. // "Leak" one object.
} }
REQUIRE(inf_pool.size() == 1+test_rounds);
} }
TEST_CASE("fixed object pool parallel test") { TEST_CASE("fixed object pool parallel test") {
......
...@@ -3,4 +3,43 @@ ...@@ -3,4 +3,43 @@
#include <rlib/condition_variable.hpp> #include <rlib/condition_variable.hpp>
#include <thread>
#include <iostream>
rlib::easy_condition_variable rcv, rcv_done;
volatile int globalTestVar = 0;
void t1() {
rcv.wait();
globalTestVar *= 3;
rcv_done.notify_all();
}
void t2() {
rcv.wait();
globalTestVar *= 2;
rcv_done.notify_all();
}
void t3() {
globalTestVar += 3;
rcv.notify_one();
rcv_done.wait();
}
TEST_CASE("condition_variable_1") {
const auto tests = 512;
std::cout << "Running tests... It may be slow." << std::endl;
for(auto cter = 0; cter < 1024; ++cter) {
globalTestVar = 0;
auto th1 = std::thread(t1);
auto th2 = std::thread(t2);
auto th3 = std::thread(t3);
th3.join();
REQUIRE((globalTestVar == 9 || globalTestVar == 6));
rcv.notify_all();
th1.join();
th2.join();
REQUIRE(globalTestVar == 18);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment