commit b4fc91f41be76d8764e849fba9fdfd5b5dd284df Author: chatlanin Date: Mon Apr 11 10:23:05 2022 +0300 init diff --git a/README.md b/README.md new file mode 100644 index 0000000..f7d2c96 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +![actfm's logo](./logo.png) +*The actor model is well described and if you don’t know anything about it, you can read about it elsewhere.* + +**This Actor Model behaves as follows:** +- An Actor is a unit of computation. It can accept a message and asynchronously perform some action based on user-specified behaviour. +- Actors have a “sendbox”, usually an in-memory queue that stores messages sent to that actor. +- Actors do not access shared state. +- Actors “own” any state they operate on, so the need for locking mechanisms is reduced*. + +**Here’s how it work:** +- Client code define the type of the message an actor can handle, and the type of the result produced by that actor using template parameters. In other words, the actors are statically typed. +- There have a simple actor interface. Clients send a message to an actor in two ways: actor.send if they don’t expect a response, or actor.expect if a response is required. +- Actor systems are instantiated with a thread pool onto which work dispatched. +- Actor systems are instantiated with a scheduler which handle the dispatching of tasks onto the thread pool in a fair manner. diff --git a/bin/main.cpp b/bin/main.cpp new file mode 100644 index 0000000..1a6815e --- /dev/null +++ b/bin/main.cpp @@ -0,0 +1,43 @@ +#include "actfm.hpp" + +#include "logger/logger.hpp" + +using result_t = std::vector; + +struct message +{ + result_t data; +}; + +class sorting : public actfm::actor +{ + public: + result_t set_message(message ms, actfm::actor* ac = nullptr) override + { + result_t res; + + if (ac) + {} + else + { + std::sort(ms.data.begin(), ms.data.end()); + } + return res; + + } +}; + +int main(int argc, char *argv[]) +{ + hack::log()("run example"); + + message ms; + ms.data = { 1, 5, 7, 9, 2, 4, 6, 8 }; + + sorting sort; + sort.set_message(ms); + + actfm::actor_controller::instance().set_actro(sort); + + hack::log()("completed"); +} diff --git a/bin/meson.build b/bin/meson.build new file mode 100644 index 0000000..64c8ac4 --- /dev/null +++ b/bin/meson.build @@ -0,0 +1,10 @@ +src = [ 'main.cpp' ] + +deps += actfm_dep + +executable( + 'actorfm', + src, + dependencies : deps, + cpp_args: args +) diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..3e5565c Binary files /dev/null and b/logo.png differ diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..2bb4e1f --- /dev/null +++ b/meson.build @@ -0,0 +1,37 @@ +# https://pixorblog.wordpress.com/2019/07/27/a-meson-starter-script-for-c-projects +project( + 'actorfm', + 'cpp', + version : '0.0.1', + default_options : ['cpp_std=c++2a'] +) + +add_project_arguments ( + '-Wpedantic', + '-Wshadow', + '-Wno-comment', + '-Wunused-but-set-variable', + language: 'cpp' +) + +compiler = meson.get_compiler('cpp') +if compiler.get_id() == 'gcc' + message('Compiler: GCC') +elif compiler.get_id() == 'clang' + message('Compiler: LLVM/clang') +endif + +deps = [ + dependency('threads'), +] + +inc = [] +inc += include_directories('.', join_paths('.', 'subprojects')) + +args = [] +hack = subproject('hack') +deps += hack.get_variable('logger_dep') + +subdir('src') +subdir('bin') +#subdir('tests') diff --git a/run b/run new file mode 100755 index 0000000..6ecb493 --- /dev/null +++ b/run @@ -0,0 +1,15 @@ +#!/bin/sh + +PROJECT_NAME="actorfm" +TEST="meson test -C build" +RUN="./build/bin/$PROJECT_NAME" + +command meson compile -C build + +if [[ $1 == "test" ]]; then + command $TEST +else + command $RUN +fi + +return 0 diff --git a/src/actfm.hpp b/src/actfm.hpp new file mode 100644 index 0000000..a4f834f --- /dev/null +++ b/src/actfm.hpp @@ -0,0 +1,3 @@ +#include "actor.hpp" +#include "actor_controller.hpp" + diff --git a/src/actor.hpp b/src/actor.hpp new file mode 100644 index 0000000..00a6339 --- /dev/null +++ b/src/actor.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace actfm +{ + template + class actor + { + public: + virtual ~actor() {} + + public: + virtual result_t set_message(message_t ms, actor* ac = nullptr) = 0; + + void send(message_t ms, actor* ac = nullptr) + {} + + result_t expect(message_t ms, actor* ac = nullptr) + {} + }; +} + diff --git a/src/actor_controller.hpp b/src/actor_controller.hpp new file mode 100644 index 0000000..0c84860 --- /dev/null +++ b/src/actor_controller.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "scheduler.hpp" + +namespace actfm +{ + class actor_controller + { + public: + actor_controller() : sch { std::make_unique() } {} + + static actor_controller& instance() { static actor_controller ac; return ac; } + + template + void set_actro(actor_t& actor) + { + sch->set_actor(actor); + } + + private: + std::unique_ptr sch; + }; +} diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 0000000..7db122e --- /dev/null +++ b/src/meson.build @@ -0,0 +1,16 @@ +inc += include_directories('.') + +subdir('thread_pool') +deps += thread_pool_dep + +lib = library( + 'actfm', + include_directories : inc, + dependencies : deps, + cpp_args: args +) + +actfm_dep = declare_dependency( + include_directories: inc, + link_with: lib, +) diff --git a/src/scheduler.hpp b/src/scheduler.hpp new file mode 100644 index 0000000..806765b --- /dev/null +++ b/src/scheduler.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "thread_pool/thread_pool.hpp" + +#include "logger/logger.hpp" + +namespace actfm +{ + class scheduler + { + public: + scheduler() : th_pool { std::make_unique() } + { + + + } + + template + void set_actor(actor_t& actor) + { + hack::log()("ref semantic"); + } + + template + void set_actor(actor_t&& actor) + { + hack::log()("move semantic"); + } + + private: + std::unique_ptr th_pool; + }; +} + diff --git a/src/thread_pool/meson.build b/src/thread_pool/meson.build new file mode 100644 index 0000000..05bc175 --- /dev/null +++ b/src/thread_pool/meson.build @@ -0,0 +1,15 @@ +headers = ['thread_pool.hpp'] +sources = ['thread_pool.cpp'] + +lib = library( + 'thread_pool', + include_directories : inc, + sources: [headers, sources], + dependencies : deps, + cpp_args: args +) + +thread_pool_dep = declare_dependency( + include_directories: inc, + link_with: lib, +) diff --git a/src/thread_pool/thread_pool.cpp b/src/thread_pool/thread_pool.cpp new file mode 100644 index 0000000..5de2b47 --- /dev/null +++ b/src/thread_pool/thread_pool.cpp @@ -0,0 +1,33 @@ +#include "thread_pool.hpp" + +namespace actfm +{ + thread_pool::thread_pool() + { + const auto thread_count = std::thread::hardware_concurrency(); + + try + { + for (auto i = 0u; i < thread_count; ++i) + pool.emplace_back(std::thread(&thread_pool::worker, this)); + } + catch (std::exception& e) + { + hack::log()(e.what()); + } + } + + thread_pool::~thread_pool() + { + done = true; + hack::log()("thread_pool completed"); + } + + void thread_pool::worker() + { + while (!done) + { + hack::log()("run thread"); + } + }; +} diff --git a/src/thread_pool/thread_pool.hpp b/src/thread_pool/thread_pool.hpp new file mode 100644 index 0000000..f1f98be --- /dev/null +++ b/src/thread_pool/thread_pool.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +#include "logger/logger.hpp" + +namespace actfm +{ + class thread_pool + { + using Pool = std::vector; + + public: + thread_pool(); + ~thread_pool(); + + private: + void worker(); + + private: + Pool pool; + bool done { false }; + }; +} diff --git a/src/threadsafe_queue.hpp b/src/threadsafe_queue.hpp new file mode 100644 index 0000000..e369c7d --- /dev/null +++ b/src/threadsafe_queue.hpp @@ -0,0 +1,15 @@ +#pragma once + +namespace actfm +{ + template + class threadsafe_queue + { + + private: + struct node + { + + }; + }; +} diff --git a/subprojects/gtest.wrap b/subprojects/gtest.wrap new file mode 100644 index 0000000..730de1a --- /dev/null +++ b/subprojects/gtest.wrap @@ -0,0 +1,15 @@ +[wrap-file] +directory = googletest-release-1.11.0 +source_url = https://github.com/google/googletest/archive/release-1.11.0.tar.gz +source_filename = gtest-1.11.0.tar.gz +source_hash = b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5 +patch_filename = gtest_1.11.0-2_patch.zip +patch_url = https://wrapdb.mesonbuild.com/v2/gtest_1.11.0-2/get_patch +patch_hash = 764530d812ac161c9eab02a8cfaec67c871fcfc5548e29fd3d488070913d4e94 + +[provide] +gtest = gtest_dep +gtest_main = gtest_main_dep +gmock = gmock_dep +gmock_main = gmock_main_dep + diff --git a/subprojects/hack.wrap b/subprojects/hack.wrap new file mode 100644 index 0000000..06d49f7 --- /dev/null +++ b/subprojects/hack.wrap @@ -0,0 +1,6 @@ +[wrap-git] +url = https://github.com/azchatlanin/hack.git +revision = master + +[provide] +hack = hack_dep diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..e69de29