completed

This commit is contained in:
chatlanin 2022-04-14 13:35:49 +03:00
parent 40399456ba
commit 49852dcac0
13 changed files with 174 additions and 160 deletions

View File

@ -33,14 +33,15 @@ int main(int argc, char *argv[])
{ {
hack::log()("run example"); hack::log()("run example");
message ms;
ms.data = { 1, 5, 7, 9, 2, 4, 6, 8 };
sorting sort; sorting sort;
actorfm::actor_controller::instance().set_actro(sort); message ms { result_t{ 1, 5, 7, 9, 2, 4, 6, 8 } };
actorfm::actor_controller::instance().set_actor(sort);
auto fut = sort.expect(ms); auto fut = sort.expect(ms);
hack::log(": ")("final result", fut.get()); hack::log(": ")("final result", fut.get());
actorfm::actor_controller::instance().remove_actor(sort);
actorfm::actor_controller::instance().destroy();
hack::log()("completed"); hack::log()("completed");
} }

View File

@ -1,6 +1,6 @@
src = [ 'main.cpp' ] src = [ 'main.cpp' ]
deps += actfm_dep deps += actorfm_dep
executable( executable(
'actorfm', 'actorfm',

View File

@ -1,4 +1,3 @@
# https://pixorblog.wordpress.com/2019/07/27/a-meson-starter-script-for-c-projects
project( project(
'actorfm', 'actorfm',
'cpp', 'cpp',

View File

@ -9,30 +9,32 @@
namespace actorfm namespace actorfm
{ {
using task_pool = threadsafe_queue<std::unique_ptr<callable>>;
template<typename message_t, typename result_t> template<typename message_t, typename result_t>
class actor class actor
{ {
public: public:
actor() = default;
virtual ~actor() {} virtual ~actor() {}
public: public:
virtual result_t invoke(message_t ms, actor* ac = nullptr) = 0; virtual result_t invoke(message_t ms, actor* ac = nullptr) = 0;
void send(message_t ms, actor* ac = nullptr)
{}
std::future<result_t> expect(message_t ms, actor* ac = nullptr) std::future<result_t> expect(message_t ms, actor* ac = nullptr)
{ {
auto func = [this, ms, ac]() { this->invoke(ms, ac); }; // TODO:: make std::move(ms) auto func = [this, ms, ac]() { return this->invoke(ms, ac); }; // TODO:: maybe make std::move(ms)
std::packaged_task<result_t()> pt = std::packaged_task<result_t()>{ func }; // TODO:: make result_t() std::packaged_task<result_t()> pt = std::packaged_task<result_t()>{ func };
auto fut = pt.get_future(); auto fut = pt.get_future();
std::unique_ptr<callable> task { new callable { std::move(fut) } }; std::unique_ptr<callable> task { new callable { std::move(pt) } };
task_queue.push(std::move(task)); task_queue.push(std::move(task));
return fut; return fut;
} }
task_pool* get_task_queue() { return &task_queue; }
private: private:
threadsafe_queue<callable> task_queue; task_pool task_queue;
}; };
} }

View File

@ -14,11 +14,16 @@ namespace actorfm
static actor_controller& instance() { static actor_controller ac; return ac; } static actor_controller& instance() { static actor_controller ac; return ac; }
template<typename actor_t> template<typename actor_t>
void set_actro(actor_t& actor) void set_actor(actor_t& actor)
{ {
sch->set_actor(actor); sch->set_actor(actor);
} }
template<typename actor_t>
void remove_actor(actor_t& actor) { sch->remove_actor(actor); }
void destroy() { sch->destroy(); }
private: private:
std::unique_ptr<scheduler> sch; std::unique_ptr<scheduler> sch;
}; };

View File

@ -1,2 +1,4 @@
#pragma once
#include "actor_impl/actor.hpp" #include "actor_impl/actor.hpp"
#include "actor_impl/actor_controller.hpp" #include "actor_impl/actor_controller.hpp"

View File

@ -2,41 +2,55 @@
#include <memory> #include <memory>
class callable namespace actorfm
{ {
public: class callable
template<typename func> {
callable(func&& f) : impl { std::make_unique<callable_base>(new callable_impl<func>(std::move(f))) } {} public:
callable(callable&& other) : impl { std::move(other.impl) } {} template<typename func>
callable() = default; callable(func&& f)
callable& operator=(callable&& other) {
{ impl = std::unique_ptr<callable_base>{new callable_impl<func>(std::move(f))};
impl = std::move(other.impl); }
return *this; callable(callable&& other) : impl { std::move(other.impl) } {}
} callable() = default;
callable& operator=(callable&& other)
{
impl = std::move(other.impl);
return *this;
}
callable(const callable&) = delete; callable(const callable&) = delete;
callable(callable&) = delete; callable(callable&) = delete;
callable& operator=(const callable&) = delete; callable& operator=(const callable&) = delete;
public: public:
void operator()() { impl->call(); } void operator()() { impl->call(); }
private: private:
struct callable_base struct callable_base
{ {
virtual void call() = 0; virtual void call() = 0;
virtual ~callable_base(); virtual ~callable_base() {};
}; };
template<typename func> template<typename func>
struct callable_impl : callable_base struct callable_impl : callable_base
{ {
callable_impl(func&& f_) : f { std::move(f_) } {}; callable_impl(func&& f_) : f { std::move(f_) } {};
void call() override { f(); } void call() override { f(); }
func f; func f;
}; };
std::unique_ptr<callable_base> impl; template<typename func>
}; struct callable_impl<std::unique_ptr<func>> : callable_base
{
callable_impl(func f_) : f { std::move(f_) } {};
void call() override { f(); }
func f;
};
std::unique_ptr<callable_base> impl;
};
}

View File

@ -4,13 +4,13 @@ subdir('thread_pool')
deps += thread_pool_dep deps += thread_pool_dep
lib = library( lib = library(
'actfm', 'actorfm',
include_directories : inc, include_directories : inc,
dependencies : deps, dependencies : deps,
cpp_args: args cpp_args: args
) )
actfm_dep = declare_dependency( actorfm_dep = declare_dependency(
include_directories: inc, include_directories: inc,
link_with: lib, link_with: lib,
) )

View File

@ -3,6 +3,7 @@
#include <memory> #include <memory>
#include "thread_pool/thread_pool.hpp" #include "thread_pool/thread_pool.hpp"
#include "threadsafe_containers/threadsafe_list.hpp"
#include "logger/logger.hpp" #include "logger/logger.hpp"
@ -11,7 +12,7 @@ namespace actorfm
class scheduler class scheduler
{ {
public: public:
scheduler() : th_pool { std::make_unique<thread_pool>() } scheduler() : th_pool { std::make_unique<thread_pool>() } , done { true }
{ {
auto f = [this]() { return this->schedul(); }; auto f = [this]() { return this->schedul(); };
th_pool->submit(callable { std::move(f) }); th_pool->submit(callable { std::move(f) });
@ -20,23 +21,38 @@ namespace actorfm
template<typename actor_t> template<typename actor_t>
void set_actor(actor_t& actor) void set_actor(actor_t& actor)
{ {
hack::log()("ref semantic"); if (done)
work_list.push_front(actor.get_task_queue());
} }
template<typename actor_t> template<typename actor_t>
void set_actor(actor_t&& actor) void remove_actor(actor_t& actor)
{ {
hack::log()("move semantic"); work_list.remove_if([&actor](threadsafe_queue<std::unique_ptr<callable>> *tasks) { return tasks == actor.get_task_queue(); });
} }
void destroy() { done = false; }
private: private:
void schedul() void schedul()
{ {
hack::log()("shudle"); while (done)
{
work_list.for_each([this](threadsafe_queue<std::unique_ptr<callable>> *tasks) {
while (!tasks->empty())
{
std::shared_ptr<std::unique_ptr<callable>> task = tasks->wait_and_pop();
th_pool->submit(std::move(*(*task)));
task = nullptr;
}
});
}
} }
private: private:
std::unique_ptr<thread_pool> th_pool; std::unique_ptr<thread_pool> th_pool;
threadsafe_list<threadsafe_queue<std::unique_ptr<callable>>*> work_list;
std::atomic<bool> done;
}; };
} }

View File

@ -1,10 +1,13 @@
#include "thread_pool.hpp" #include "thread_pool.hpp"
#include "logger/logger.hpp"
namespace actorfm namespace actorfm
{ {
thread_pool::thread_pool() : jn { th } thread_pool::thread_pool() : done { false }, jn { th }
{ {
const auto thread_count = std::thread::hardware_concurrency(); auto thread_count = std::thread::hardware_concurrency();
thread_count = thread_count == 0 ? 2 : thread_count;
try try
{ {
@ -13,14 +16,13 @@ namespace actorfm
} }
catch (std::exception& e) catch (std::exception& e)
{ {
hack::log()(e.what()); hack::error()(e.what());
} }
} }
thread_pool::~thread_pool() thread_pool::~thread_pool()
{ {
done = true; done = true;
hack::log()("thread_pool completed");
} }
void thread_pool::worker() void thread_pool::worker()

View File

@ -6,8 +6,6 @@
#include "callable.hpp" #include "callable.hpp"
#include "threadsafe_containers/threadsafe_queue.hpp" #include "threadsafe_containers/threadsafe_queue.hpp"
#include "logger/logger.hpp"
namespace actorfm namespace actorfm
{ {
class thread_pool class thread_pool
@ -39,7 +37,8 @@ namespace actorfm
private: private:
threads& th; threads& th;
}; };
std::atomic<bool> done { false };
std::atomic<bool> done;
threads th; threads th;
pool pl; pool pl;
joiner jn; joiner jn;

View File

@ -4,89 +4,76 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
template<typename data_t> namespace actorfm
class threadsafe_list
{ {
public: template<typename data_t>
threadsafe_list() = default; class threadsafe_list
~threadsafe_list() {
{ public:
threadsafe_list() = default;
}; ~threadsafe_list()
threadsafe_list(const threadsafe_list&) = delete;
threadsafe_list& operator=(const threadsafe_list&) = delete;
public:
void push_front(const data_t& value)
{
std::unique_ptr<node> new_node { new node { value } };
}
template <typename func>
void for_each(func f)
{
node *current = &head;
std::unique_lock lk { head.m };
while (node* const next = current->next.get())
{ {
std::unique_lock next_lk { next->m }; remove_if([](node const &) { return true; });
lk.unlock(); };
f(*next->data);
current = next; threadsafe_list(const threadsafe_list&) = delete;
lk = std::move(next_lk); threadsafe_list& operator=(const threadsafe_list&) = delete;
public:
void push_front(const data_t& value)
{
std::unique_ptr<node> new_node { new node { value } };
std::lock_guard lk { head.m };
new_node->next = std::move(head.next);
head.next = std::move(new_node);
} }
}
template <typename func> template <typename func>
std::shared_ptr<data_t> find_first_if(func f) void for_each(func f)
{
node *current = &head;
std::unique_lock lk { head.m };
while (node *const next = current->next.get())
{ {
std::unique_lock next_lk { next->m }; node *current = &head;
lk.unlock(); std::unique_lock lk { head.m };
if (f(*next->data)) while (node* const next = current->next.get())
return next->data;
current = next;
lk = std::move(next_lk);
}
return std::shared_ptr<data_t>();
}
template <typename func>
void remove_if(func f)
{
node *current = &head;
std::unique_lock lk { head.m };
while (node *const next = current->next.get())
{
std::unique_lock next_lk { next->m };
if (f(*next->data))
{
std::unique_ptr<node> old_next = std::move(current->next);
current->next = std::move(next->next);
next_lk.unlock();
}
else
{ {
std::unique_lock next_lk { next->m };
lk.unlock(); lk.unlock();
f(*next->data);
current = next; current = next;
lk = std::move(next_lk); lk = std::move(next_lk);
} }
} }
}
private: template <typename func>
struct node void remove_if(func f)
{ {
std::mutex m; node *current = &head;
std::shared_ptr<data_t> data; std::unique_lock lk { head.m };
std::unique_ptr<node> next; while (node *const next = current->next.get())
node() : next() {} {
node(const data_t& value) : data { std::make_shared<data_t>(value) } {}; std::unique_lock next_lk { next->m };
}; if (f(*next->data))
{
std::unique_ptr<node> old_next = std::move(current->next);
current->next = std::move(next->next);
next_lk.unlock();
}
else
{
lk.unlock();
current = next;
lk = std::move(next_lk);
}
}
}
node head; private:
}; struct node
{
std::mutex m;
std::shared_ptr<data_t> data;
std::unique_ptr<node> next;
node() : next() {}
node(const data_t& value) : data { std::make_shared<data_t>(value) } {};
} head;
};
}

View File

@ -18,7 +18,7 @@ namespace actorfm
public: public:
std::shared_ptr<data_t> try_pop() std::shared_ptr<data_t> try_pop()
{ {
std::unique_ptr<data_t> old_head = try_pop_head(); std::unique_ptr<node> old_head = try_pop_head();
return old_head ? old_head->data : std::shared_ptr<data_t>(); return old_head ? old_head->data : std::shared_ptr<data_t>();
} }
@ -26,9 +26,7 @@ namespace actorfm
{ {
std::unique_ptr<node> old_head = try_pop_head(value); std::unique_ptr<node> old_head = try_pop_head(value);
if (old_head) if (old_head)
{
return true; return true;
}
return false; return false;
} }
@ -38,19 +36,14 @@ namespace actorfm
return old_head->data; return old_head->data;
} }
void wait_and_pop(data_t& value)
{
std::unique_ptr<node> old_head = wait_pop_head(value);
}
void push(data_t new_value) void push(data_t new_value)
{ {
std::shared_ptr<data_t> new_data { std::make_shared<data_t>(std::move(new_value)) }; std::shared_ptr<data_t> new_data { std::make_shared<data_t>(std::move(new_value)) };
std::unique_ptr<node> p { new node }; std::unique_ptr<node> p { new node };
{ {
std::lock_guard tail_lock { tail_mutex }; std::lock_guard tail_lock { tail_mutex };
tail->data = new_data;
node* const new_tail = p.get(); node* const new_tail = p.get();
tail->data = new_data;
tail->next = std::move(p); tail->next = std::move(p);
tail = new_tail; tail = new_tail;
} }
@ -60,7 +53,7 @@ namespace actorfm
bool empty() bool empty()
{ {
std::lock_guard head_lock { head_mutex }; std::lock_guard head_lock { head_mutex };
return (head == get_tail()); return head.get() == get_tail();
} }
private: private:
@ -73,18 +66,11 @@ namespace actorfm
std::condition_variable cv; std::condition_variable cv;
std::mutex head_mutex; std::mutex head_mutex;
std::mutex tail_mutex; std::mutex tail_mutex;
std::unique_ptr<node> head; std::unique_ptr<node> head;
node* tail; node* tail;
private: private:
std::unique_ptr<node> try_pop_head()
{
std::lock_guard head_lock { head_mutex };
if(head.get() == get_tail())
return std::unique_ptr<node>();
return pop_head();
}
std::unique_ptr<node> try_pop_head(data_t& value) std::unique_ptr<node> try_pop_head(data_t& value)
{ {
std::lock_guard head_lock { head_mutex }; std::lock_guard head_lock { head_mutex };
@ -101,10 +87,18 @@ namespace actorfm
return old_head; return old_head;
} }
std::unique_ptr<node> try_pop_head()
{
std::lock_guard head_lock { head_mutex };
if(head.get() == get_tail())
return std::unique_ptr<node>();
return pop_head();
}
std::unique_lock<std::mutex> wait_for_data() std::unique_lock<std::mutex> wait_for_data()
{ {
std::unique_lock head_lock { head_mutex }; std::unique_lock head_lock { head_mutex };
cv.wait(head_lock, [&] { return head != get_tail(); }); cv.wait(head_lock, [&] { return head.get() != get_tail(); });
return head_lock; return head_lock;
} }
@ -114,13 +108,6 @@ namespace actorfm
return pop_head(); return pop_head();
} }
std::unique_ptr<node> wait_pop_head(data_t& value)
{
std::unique_lock head_lock { wait_for_data() };
value = std::move(*head->data);
return pop_head();
}
node* get_tail() node* get_tail()
{ {
std::lock_guard tail_lock { tail_mutex }; std::lock_guard tail_lock { tail_mutex };