{"id":18720483,"url":"https://github.com/stiffstream/sobjectizer","last_synced_at":"2025-05-15T20:00:43.705Z","repository":{"id":48144203,"uuid":"186988663","full_name":"Stiffstream/sobjectizer","owner":"Stiffstream","description":"An implementation of Actor, Publish-Subscribe, and CSP models in one rather small C++ framework. With performance, quality, and stability proved by years in the production.","archived":false,"fork":false,"pushed_at":"2024-10-25T04:38:14.000Z","size":14738,"stargazers_count":479,"open_issues_count":10,"forks_count":47,"subscribers_count":20,"default_branch":"master","last_synced_at":"2024-10-25T15:47:27.107Z","etag":null,"topics":["actor","actor-framework","actor-library","actor-model","actors","agents","communicating-sequential-processes","concurrency","concurrent-programming","cplusplus","cplusplus-17","cpp","csp","message-passing","multithreading","publish-subscribe","pubsub","sobjectizer","thread"],"latest_commit_sha":null,"homepage":"https://stiffstream.com/en/products/sobjectizer.html","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Stiffstream.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-16T08:45:51.000Z","updated_at":"2024-10-20T17:49:39.000Z","dependencies_parsed_at":"2023-09-23T17:52:42.579Z","dependency_job_id":"83fab3e4-bd3b-475f-b424-e1cbc7af9299","html_url":"https://github.com/Stiffstream/sobjectizer","commit_stats":{"total_commits":1008,"total_committers":7,"mean_commits":144.0,"dds":0.02182539682539686,"last_synced_commit":"3e140e4ef9766e46068bdc036795bebeb11f0bb5"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fsobjectizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fsobjectizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fsobjectizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stiffstream%2Fsobjectizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stiffstream","download_url":"https://codeload.github.com/Stiffstream/sobjectizer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254414457,"owners_count":22067263,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actor","actor-framework","actor-library","actor-model","actors","agents","communicating-sequential-processes","concurrency","concurrent-programming","cplusplus","cplusplus-17","cpp","csp","message-passing","multithreading","publish-subscribe","pubsub","sobjectizer","thread"],"created_at":"2024-11-07T13:31:16.344Z","updated_at":"2025-05-15T20:00:42.958Z","avatar_url":"https://github.com/Stiffstream.png","language":"C++","readme":"* [What is SObjectizer?](#what-is-sobjectizer)\n* [What distinguishes SObjectizer?](#what-distinguishes-sobjectizer)\n\t* [SObjectizer is not like TBB, taskflow or HPX](#sobjectizer-is-not-like-tbb-taskflow-or-hpx)\n* [Show me the code!](#show-me-the-code)\n\t* [HelloWorld example](#helloworld-example)\n\t* [Ping-Pong example](#ping-pong-example)\n\t* [Pub/Sub example](#pubsub-example)\n\t* [BlinkingLed example](#blinkingled-example)\n\t* [CSP-like Ping-Pong example](#csp-like-ping-pong-example)\n\t* [Another CSP-example with Golang's like select() statement](#another-csp-example-with-golangs-like-select-statement)\n\t* [Want to know more?](#want-to-know-more)\n* [There are more useful stuff in a companion project so5extra](#there-are-more-useful-stuff-in-a-companion-project-so5extra)\n* [Limitations](#limitations)\n* [Obtaining and building](#obtaining-and-building)\n\t* [SObjectizer-5.8 requires Cpp-17!](#sobjectizer-58-requires-c17)\n\t* [Building via Mxx_ru](#building-via-mxx_ru)\n\t* [Building via CMake](#building-via-cmake)\n\t* [Building for Android](#building-for-android)\n\t\t* [Building with Android NDK](#building-with-android-ndk)\n\t\t* [Building with CrystaX NDK](#building-with-crystax-ndk)\n\t* [Using C   Dependency Managers](#using-c-dependency-managers)\n\t\t* [Using via vcpkg](#using-via-vcpkg)\n\t\t* [Using via Conan](#using-via-conan)\n\t\t\t* [Installing SObjectizer And Adding It To conanfile.txt](#installing-sobjectizer-and-adding-it-to-conanfiletxt)\n\t\t\t* [Adding SObjectizer To Your CMakeLists.txt](#adding-sobjectizer-to-your-cmakeliststxt)\n* [License](#license)\n\nCreated by [gh-md-toc](https://github.com/ekalinin/github-markdown-toc.go)\n\n# What is SObjectizer?\n\nSObjectizer is one of a few cross-platform and OpenSource \"actor frameworks\"\nfor C++. But SObjectizer supports not only Actor Model, but also\nPublish-Subscribe Model and CSP-like channels. The goal of SObjectizer is\nsignificant simplification of development of concurrent and multithreaded\napplications in C++.\n\nSObjectizer allows the creation of a concurrent app as a set of agent-objects\nwhich interact with each other through asynchronous messages. It handles\nmessage dispatching and provides a working context for message processing. And\nallows to tune those things by supplying various ready-to-use dispatchers.\n\n# What distinguishes SObjectizer?\n\n**Maturity**. SObjectizer is based on ideas that have been put forward in\n1995-2000. And SObjectizer itself is being developed since 2002. SObjectizer-5\nis continuously evolved since 2010.\n\n**Stability**. From the very beginning SObjectizer was used for\nbusiness-critical applications, and some of them are still being used in\nproduction. Breaking changes in SObjectizer are rare and we approach to them\nvery carefully.\n\n**Cross-platform**. SObjectizer runs on Windows, Linux, FreeBSD, macOS and Android.\n\n**Easy-to-use**. SObjectizer provides easy to understand and easy to use API\nwith a lot of examples in the SObjectizer's distributive and a plenty of\ninformation in the project's Wiki.\n\n**Free**. SObjectizer is distributed under BSD-3-CLAUSE license, so it can be\nused in development of proprietary commercial software for free.\n\n## SObjectizer is not like TBB, taskflow or HPX\n\nSObjectizer is often compared with tools like Intel Threading Building Blocks, taskflow, HPX, and similar to them. Such comparison is just useless.\n\nAll those tools are intended to be used for solving tasks from Parallel Computing area: they allow to reduce the computational time by utilizing several CPU cores. For example, you can reencode your video file from one format to another within one hour on one CPU core, by it takes only 15 minutes on four cores. That is the main goal of Parallel Computing.\n\nSObjectizer is intended for a slightly different area: Concurrent Computing. The main goal of SObjectizer is the simplification of doing many different tasks at once. Sometimes there is no need to use more than just one CPU core for that. But if there are several CPU cores, then SObjectizer makes the handling of those tasks and the interaction between them much easier.\n\nThe tricky part is the fact that Parallel- and Concurrent Computing use the same concurrency mechanisms and primitives (like threads, mutexes, atomics, and so on) under the hood. But from the high-level point of view Parallel- and Concurrent Computing are used for very different tasks.\n\nAs examples of applications that were or could be implemented on top of SObjectizer, we can list multithreaded proxy-server, automatic control system, MQ-broker, database server, and so on.\n\n# Show me the code!\n\n## HelloWorld example\n\nThis is a classical example \"Hello, World\" expressed by using SObjectizer's\nagents:\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\nclass hello_actor final : public so_5::agent_t {\npublic:\n   using so_5::agent_t::agent_t;\n\n   void so_evt_start() override {\n      std::cout \u003c\u003c \"Hello, World!\" \u003c\u003c std::endl;\n      // Finish work of example.\n      so_deregister_agent_coop_normally();\n   }\n};\n\nint main() {\n   // Launch SObjectizer.\n   so_5::launch([](so_5::environment_t \u0026 env) {\n         // Add a hello_actor instance in a new cooperation.\n         env.register_agent_as_coop( env.make_agent\u003chello_actor\u003e() );\n      });\n\n   return 0;\n}\n```\n\n## Ping-Pong example\n\nLet's look at more interesting example with two agents and message exchange\nbetween them. It is another famous example for actor frameworks, \"Ping-Pong\":\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\nstruct ping {\n   int counter_;\n};\n\nstruct pong {\n   int counter_;\n};\n\nclass pinger final : public so_5::agent_t {\n   so_5::mbox_t ponger_;\n\n   void on_pong(mhood_t\u003cpong\u003e cmd) {\n      if(cmd-\u003ecounter_ \u003e 0)\n         so_5::send\u003cping\u003e(ponger_, cmd-\u003ecounter_ - 1);\n      else\n         so_deregister_agent_coop_normally();\n   }\n\npublic:\n   pinger(context_t ctx) : so_5::agent_t{std::move(ctx)} {}\n\n   void set_ponger(const so_5::mbox_t mbox) { ponger_ = mbox; }\n\n   void so_define_agent() override {\n      so_subscribe_self().event( \u0026pinger::on_pong );\n   }\n\n   void so_evt_start() override {\n      so_5::send\u003cping\u003e(ponger_, 1000);\n   }\n};\n\nclass ponger final : public so_5::agent_t {\n   const so_5::mbox_t pinger_;\n   int pings_received_{};\n\npublic:\n   ponger(context_t ctx, so_5::mbox_t pinger)\n      :  so_5::agent_t{std::move(ctx)}\n      ,  pinger_{std::move(pinger)}\n   {}\n\n   void so_define_agent() override {\n      so_subscribe_self().event(\n         [this](mhood_t\u003cping\u003e cmd) {\n            ++pings_received_;\n            so_5::send\u003cpong\u003e(pinger_, cmd-\u003ecounter_);\n         });\n   }\n\n   void so_evt_finish() override {\n      std::cout \u003c\u003c \"pings received: \" \u003c\u003c pings_received_ \u003c\u003c std::endl;\n   }\n};\n\nint main() {\n   so_5::launch([](so_5::environment_t \u0026 env) {\n         env.introduce_coop([](so_5::coop_t \u0026 coop) {\n               auto pinger_actor = coop.make_agent\u003cpinger\u003e();\n               auto ponger_actor = coop.make_agent\u003cponger\u003e(\n                     pinger_actor-\u003eso_direct_mbox());\n\n               pinger_actor-\u003eset_ponger(ponger_actor-\u003eso_direct_mbox());\n            });\n      });\n\n   return 0;\n}\n```\n\nAll agents in the code above are working on the same work thread. How to bind\nthem to different work threads?\n\nIt is very simple. Just use an appropriate dispatcher:\n\n```cpp\nint main() {\n   so_5::launch([](so_5::environment_t \u0026 env) {\n         env.introduce_coop(\n            so_5::disp::active_obj::make_dispatcher(env).binder(),\n            [](so_5::coop_t \u0026 coop) {\n               auto pinger_actor = coop.make_agent\u003cpinger\u003e();\n               auto ponger_actor = coop.make_agent\u003cponger\u003e(\n                     pinger_actor-\u003eso_direct_mbox());\n\n               pinger_actor-\u003eset_ponger(ponger_actor-\u003eso_direct_mbox());\n            });\n      });\n\n   return 0;\n}\n```\n\n## Pub/Sub example\n\nSObjectizer supports Pub/Sub model via multi-producer/multi-consumer message\nboxes. A message sent to that message box will be received by all subscribers\nof that message type:\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\nusing namespace std::literals;\n\nstruct acquired_value {\n   std::chrono::steady_clock::time_point acquired_at_;\n   int value_;\n};\n\nclass producer final : public so_5::agent_t {\n   const so_5::mbox_t board_;\n   so_5::timer_id_t timer_;\n   int counter_{};\n\n   struct acquisition_time final : public so_5::signal_t {};\n\n   void on_timer(mhood_t\u003cacquisition_time\u003e) {\n      // Publish the next value for all consumers.\n      so_5::send\u003cacquired_value\u003e(\n            board_, std::chrono::steady_clock::now(), ++counter_);\n   }\n\npublic:\n   producer(context_t ctx, so_5::mbox_t board)\n      :  so_5::agent_t{std::move(ctx)}\n      ,  board_{std::move(board)}\n   {}\n\n   void so_define_agent() override {\n      so_subscribe_self().event(\u0026producer::on_timer);\n   }\n\n   void so_evt_start() override {\n      // Agent will periodically recive acquisition_time signal\n      // without initial delay and with period of 750ms.\n      timer_ = so_5::send_periodic\u003cacquisition_time\u003e(*this, 0ms, 750ms);\n   }\n};\n\nclass consumer final : public so_5::agent_t {\n   const so_5::mbox_t board_;\n   const std::string name_;\n\n   void on_value(mhood_t\u003cacquired_value\u003e cmd) {\n      std::cout \u003c\u003c name_ \u003c\u003c \": \" \u003c\u003c cmd-\u003evalue_ \u003c\u003c std::endl;\n   }\n\npublic:\n   consumer(context_t ctx, so_5::mbox_t board, std::string name)\n      :  so_5::agent_t{std::move(ctx)}\n      ,  board_{std::move(board)}\n      ,  name_{std::move(name)}\n   {}\n\n   void so_define_agent() override {\n      so_subscribe(board_).event(\u0026consumer::on_value);\n   }\n};\n\nint main() {\n   so_5::launch([](so_5::environment_t \u0026 env) {\n         auto board = env.create_mbox();\n         env.introduce_coop([board](so_5::coop_t \u0026 coop) {\n               coop.make_agent\u003cproducer\u003e(board);\n               coop.make_agent\u003cconsumer\u003e(board, \"first\"s);\n               coop.make_agent\u003cconsumer\u003e(board, \"second\"s);\n            });\n\n         std::this_thread::sleep_for(std::chrono::seconds(4));\n         env.stop();\n      });\n\n   return 0;\n}\n```\n\n## BlinkingLed example\n\nAll agents in SObjectizer are finite-state machines. Almost all functionality\nof hierarchical finite-states machines (HSM) are supported: child states and\nhandlers inheritance, on_enter/on_exit handlers, state timeouts, deep- and\nshallow state history, except orthogonal states.\n\nLet's see how an agent that implements the following statechart can look like:\n\n![Blinking Led Statechart](dev/sample/so_5/blinking_led/statechart_horizontal.png)\n\nThis is a very simple example that demonstrates an agent for the statechart shown above:\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\nusing namespace std::literals;\n\nclass blinking_led final : public so_5::agent_t {\n   state_t off{ this }, blinking{ this },\n      blink_on{ initial_substate_of{ blinking } },\n      blink_off{ substate_of{ blinking } };\n\npublic :\n   struct turn_on_off : public so_5::signal_t {};\n\n   blinking_led(context_t ctx) : so_5::agent_t{std::move(ctx)} {\n      this \u003e\u003e= off;\n\n      off.just_switch_to\u003cturn_on_off\u003e(blinking);\n\n      blinking.just_switch_to\u003cturn_on_off\u003e(off);\n\n      blink_on\n         .on_enter([]{ std::cout \u003c\u003c \"ON\" \u003c\u003c std::endl; })\n         .on_exit([]{ std::cout \u003c\u003c \"off\" \u003c\u003c std::endl; })\n         .time_limit(1250ms, blink_off);\n\n      blink_off\n         .time_limit(750ms, blink_on);\n   }\n};\n\nint main()\n{\n   so_5::launch([](so_5::environment_t \u0026 env) {\n      so_5::mbox_t m;\n      env.introduce_coop([\u0026](so_5::coop_t \u0026 coop) {\n            auto led = coop.make_agent\u003c blinking_led \u003e();\n            m = led-\u003eso_direct_mbox();\n         });\n\n      const auto pause = [](auto duration) {\n         std::this_thread::sleep_for(duration);\n      };\n\n      std::cout \u003c\u003c \"Turn blinking on for 10s\" \u003c\u003c std::endl;\n      so_5::send\u003cblinking_led::turn_on_off\u003e(m);\n      pause(10s);\n\n      std::cout \u003c\u003c \"Turn blinking off for 5s\" \u003c\u003c std::endl;\n      so_5::send\u003cblinking_led::turn_on_off\u003e(m);\n      pause(5s);\n\n      std::cout \u003c\u003c \"Turn blinking on for 5s\" \u003c\u003c std::endl;\n      so_5::send\u003cblinking_led::turn_on_off\u003e(m);\n      pause(5s);\n\n      std::cout \u003c\u003c \"Stopping...\" \u003c\u003c std::endl;\n      env.stop();\n   } );\n\n   return 0;\n}\n```\n\n## CSP-like Ping-Pong example\n\nSObjectizer allows to write concurrent applications even without agents inside.\nOnly plain threads and CSP-like channels can be used.\n\nThis is plain-thread implementation of Ping-Pong example (please note that\nmain() is not exception-safe):\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\nstruct ping {\n   int counter_;\n};\n\nstruct pong {\n   int counter_;\n};\n\nvoid pinger_proc(so_5::mchain_t self_ch, so_5::mchain_t ping_ch) {\n   so_5::send\u003cping\u003e(ping_ch, 1000);\n\n   // Read all message until channel will be closed.\n   so_5::receive( so_5::from(self_ch).handle_all(),\n      [\u0026](so_5::mhood_t\u003cpong\u003e cmd) {\n         if(cmd-\u003ecounter_ \u003e 0)\n            so_5::send\u003cping\u003e(ping_ch, cmd-\u003ecounter_ - 1);\n         else {\n            // Channels have to be closed to break `receive` calls.\n            so_5::close_drop_content(so_5::exceptions_enabled, self_ch);\n            so_5::close_drop_content(so_5::exceptions_enabled, ping_ch);\n         }\n      });\n}\n\nvoid ponger_proc(so_5::mchain_t self_ch, so_5::mchain_t pong_ch) {\n   int pings_received{};\n\n   // Read all message until channel will be closed.\n   so_5::receive( so_5::from(self_ch).handle_all(),\n      [\u0026](so_5::mhood_t\u003cping\u003e cmd) {\n         ++pings_received;\n         so_5::send\u003cpong\u003e(pong_ch, cmd-\u003ecounter_);\n      });\n\n   std::cout \u003c\u003c \"pings received: \" \u003c\u003c pings_received \u003c\u003c std::endl;\n}\n\nint main() {\n   so_5::wrapped_env_t sobj;\n\n   auto pinger_ch = so_5::create_mchain(sobj);\n   auto ponger_ch = so_5::create_mchain(sobj);\n\n   std::thread pinger{pinger_proc, pinger_ch, ponger_ch};\n   std::thread ponger{ponger_proc, ponger_ch, pinger_ch};\n\n   ponger.join();\n   pinger.join();\n\n   return 0;\n}\n```\n\n## Another CSP-example with Golang's like select() statement\n\nSObjectizer provides a select() function that is similar to Golang's select\nstatement. This function allows waiting for incoming messages from several\nmessage chains. It also allows to wait for the readiness of message chains for\naccepting a new outgoing message. So select() allows to do non-blocking send()\ncalls with the handling of incoming messages while the target message chain is\nfull.\n\nThere is a Fibonacci calculation example that uses select() as the\nback-pressure mechanism (number producer thread will wait if number reader\nthread doesn't read the previous number yet). Note also that main() function in\nthis example is exception-safe.\n\n```cpp\n#include \u003cso_5/all.hpp\u003e\n\n#include \u003cchrono\u003e\n\nusing namespace std;\nusing namespace std::chrono_literals;\nusing namespace so_5;\n\nstruct quit {};\n\nvoid fibonacci( mchain_t values_ch, mchain_t quit_ch )\n{\n   int x = 0, y = 1;\n   mchain_select_result_t r;\n   do\n   {\n      r = select(\n         from_all().handle_n(1),\n         // Sends a new message of type 'int' with value 'x' inside\n         // when values_ch is ready for a new outgoing message.\n         send_case( values_ch, message_holder_t\u003cint\u003e::make(x),\n               [\u0026x, \u0026y] { // This block of code will be called after the send().\n                  auto old_x = x;\n                  x = y; y = old_x + y;\n               } ),\n         // Receive a 'quit' message from quit_ch if it is here.\n         receive_case( quit_ch, [](quit){} ) );\n   }\n   // Continue the loop while we send something and receive nothing.\n   while( r.was_sent() \u0026\u0026 !r.was_handled() );\n}\n\nint main()\n{\n   wrapped_env_t sobj;\n\n   thread fibonacci_thr;\n   auto thr_joiner = auto_join( fibonacci_thr );\n\n   // The chain for Fibonacci number will have limited capacity.\n   auto values_ch = create_mchain( sobj, 1s, 1,\n         mchain_props::memory_usage_t::preallocated,\n         mchain_props::overflow_reaction_t::abort_app );\n\n   auto quit_ch = create_mchain( sobj );\n   auto ch_closer = auto_close_drop_content( values_ch, quit_ch );\n\n   fibonacci_thr = thread{ fibonacci, values_ch, quit_ch };\n\n   // Read the first 10 numbers from values_ch.\n   receive( from( values_ch ).handle_n( 10 ),\n         // And show every number to the standard output.\n         []( int v ) { cout \u003c\u003c v \u003c\u003c endl; } );\n\n   send\u003c quit \u003e( quit_ch );\n}\n```\n\n## Want to know more?\n\nMore information about SObjectizer can be found in the corresponding section of\nthe [project's Wiki](https://github.com/Stiffstream/sobjectizer/wiki).\n\n# There are more useful stuff in a companion project so5extra\n\nThere is a separate companion project [so5extra](https://github.com/Stiffstream/so5extra) that contains a lot of various useful things like Asio's based dispatchers, additional types of mboxes, revocable timer, synchronous requests, and more.\n\nFor example, there is how synchronous interaction looks like (by using `so_5::extra::sync` stuff):\n\n```cpp\n#include \u003cso_5_extra/sync/pub.hpp\u003e\n\n#include \u003cso_5/all.hpp\u003e\n\n// Short alias for convenience.\nnamespace sync_ns = so_5::extra::sync;\n\nusing namespace std::chrono_literals;\n\n// The type of service provider.\nclass service_provider_t final : public so_5::agent_t\n{\npublic :\n   using so_5::agent_t::agent_t;\n\n   void so_define_agent() override\n   {\n      so_subscribe_self().event(\n            []( sync_ns::request_mhood_t\u003cint, std::string\u003e cmd ) {\n               // Transform the incoming value, convert the result\n               // to string and send the resulting string back.\n               cmd-\u003emake_reply( std::to_string(cmd-\u003erequest() * 2) );\n            } );\n   }\n};\n\n// The type of service consumer.\nclass consumer_t final : public so_5::agent_t\n{\n   // Message box of the service provider.\n   const so_5::mbox_t m_service;\n\npublic :\n   consumer_t( context_t ctx, so_5::mbox_t service )\n      :  so_5::agent_t{ std::move(ctx) }\n      ,  m_service{ std::move(service) }\n   {}\n\n   void so_evt_start() override\n   {\n      // Issue a request and wait for the result no more than 500ms.\n      auto result = sync_ns::request_reply\u003cint, std::string\u003e(\n            // The destination for the request.\n            m_service,\n            // Max waiting time.\n            500ms,\n            // Request's value.\n            4 );\n\n      std::cout \u003c\u003c \"The result: \" \u003c\u003c result \u003c\u003c std::endl;\n\n      so_deregister_agent_coop_normally();\n   }\n};\n\nint main()\n{\n   so_5::launch( [](so_5::environment_t \u0026 env) {\n      env.introduce_coop(\n         // Every agent should work on its own thread.\n         so_5::disp::active_obj::make_dispatcher( env ).binder(),\n         [](so_5::coop_t \u0026 coop) {\n            auto service_mbox = coop.make_agent\u003c service_provider_t \u003e()\n                  -\u003eso_direct_mbox();\n            coop.make_agent\u003c consumer_t \u003e( service_mbox );\n         } );\n   } );\n}\n```\n\nSObjectizer itself is intended to be a relatively small project without external dependencies. so5extra has no this constraint. That is why Asio's based dispatchers and environment infrastructures are implemented in so5extra, not in the SObjectizer.\n\nAnother significant property of SObjectizer is stability. We're trying to keep SObjectizer as stable as possible, but there is a need to try some new features, even if we don't know yet how successful and demanded they will be. so5extra is a good place to experiment with new features, some of them could be moved to the SObjectizer with time.\n\nSo if you don't find a helpful feature in the SObjectizer, let's try to look at [so5extra](https://github.com/Stiffstream/so5extra). Maybe it is already there.\n\n# Limitations\n\nSObjectizer is an in-process message dispatching framework. It doesn't support\ndistributed applications just out of box. But external tools and libraries can\nbe used in that case. Please take a look at our mosquitto_transport experiment:\nhttps://github.com/Stiffstream/mosquitto_transport\n\n# Obtaining and building\n\nSObjectizer can be checked out from [GitHub](https://github.com/stiffstream/sobjectizer). Archives with SObjectizer's source code can be downloaded\nfrom [GitHub](https://github.com/Stiffstream/sobjectizer/releases) or from [SourceForge](https://sourceforge.net/projects/sobjectizer/files/sobjectizer).\n\nThere are two ways for building SObjectizer.\nThe first one by using [Mxx_ru](https://sourceforge.net/projects/mxxru/)\ntool. The second one by using [CMake](https://cmake.org).\n\nNOTE. Since v.5.5.15.2 there is a support of Android platform.  Building for\nAndroid is possible by CMake only. See the corresponding section below.\n\nSObjectizer can also be installed and used via **vcpkg** and **Conan**\ndependency managers. See the appropriate sections below.\n\n## SObjectizer-5.8 requires C++17!\n\nThe 5.8-branch of SObjectizer requires C++17.\n\nIf you need support for C++14 or C++11 try to look to older versions of\nSObjectizer on [SourceForge](https://sourceforge.net/projects/sobjectizer).  Or\ncontact [stiffstream](https://stiffstream.com/en/services.html) to discuss\nporting of SObjectizer-5.8 to older C++ standards.\n\n## Building via Mxx_ru\n\n*NOTE. This is a standard way for building SObjectizer. This way is used in\nSObjectizer development process.*\n\nTo build SObjectizer it is necessary to use Ruby language and Mxx_ru tool.\nInstall Ruby and then install Mxx_ru via RubyGems command:\n\n```sh\ngem install Mxx_ru\n```\n\nIf you already have Mxx_ru installed please update to at least version 1.6.14.6:\n\n```sh\ngem update Mxx_ru\n```\n\nSObjectizer can be obtained from Git repository on GitHub:\n\n```sh\ngit clone https://github.com/stiffstream/sobjectizer\n```\n\nTo build SObjectizer:\n\n```sh\ncd sobjectizer/dev\nruby build.rb\n```\n\nStatic and shared library for SObjectizer will be built. Libraries will be\nplaced into target/release subdirectory.\n\nIf you want to build just shared library:\n\n```sh\ncd sobjectizer/dev\nruby so_5/prj.rb\n```\n\nOr if you want to build just static library:\n\n```sh\ncd sobjectizer/dev\nruby so_5/prj_s.rb\n```\n\nTo build SObjectizer with all tests and samples:\n\n```sh\ncd sobjectizer/dev\nruby build_all.rb\n```\n\nPlease note that under FreeBSD it could be necessary to define LD_LIBRARY_PATH\nenvironment variable. And the actual build command sequence under FreeBSD could\nbe as follows:\n\n```sh\ncd sobjectizer/dev\nexport LD_LIBRARY_PATH=target/release\nruby build_all.rb\n```\n\nTo build html-format documentation for SObjectizer the Doxygen tool is\nnecessary. If it is installed then:\n\n```sh\ncd sobjectizer/doxygen\ndoxygen\n```\n\nGenerated html-files will be located in sobjectizer/dev/doc/html.\n\nNOTE. If you do not specify MXX_RU_CPP_TOOLSET by youself then Mxx_ru will\ntry to detect your C++ toolset automatically. If you want to use C++ compiler\nwhich is not default in your system please define MXX_RU_CPP_TOOLSET\nenvironment variable manually. It could look like:\n\n```sh\nexport MXX_RU_CPP_TOOLSET=\"clang_linux compiler_name=clang++-6 linker_name=clang++-6\"\n```\n\nMore information about tuning Mxx_ru for your needs you can find in the\n[corresponding documentation](http://sourceforge.net/projects/mxxru/files/Mxx_ru%201.6/mxx_ru-1.6.4-r1.pdf/download).\n\n## Building via CMake\n\nTo build SObjectizer via CMake it is necessary to have CMake and some knowledge\nof how to use it. The following action is just a demonstration. For more \ndetailed info about cmake build system for SObjectizer see\ndev/cmake/CmakeQuickHowto.txt\n\nTo get and build SObjectizer under Linux/FreeBSD in command line run:\n\n```sh\ngit clone https://github.com/stiffstream/sobjectizer\ncd sobjectizer\nmkdir cmake_build\ncd cmake_build\ncmake -DCMAKE_INSTALL_PREFIX=target -DCMAKE_BUILD_TYPE=Release ../dev\ncmake --build . --config Release\ncmake --build . --config Release --target install\n```\n\nThose commands will create all necessary Makefile, then build SObjectizer. If\nit necessary to build examples and tests too, use\n\n```sh\ncmake -DBUILD_ALL=ON -DCMAKE_INSTALL_PREFIX=target ../dev\n```\n\nWhen 'make install' finished './target' will contain two subfolders\n'./bin' with samples and './lib' with shared libso.5.x.x.so\n\nCMake build system currently supports this options:\n\n* `SOBJECTIZER_BUILD_STATIC`. Enable building SObjectizer as a static library [default: ON]\n* `SOBJECTIZER_BUILD_SHARED`. Enable building SObjectizer as a shared library [default: ON]\n* `BUILD_ALL`. Enable building examples and tests [default: OFF]\n* `BUILD_EXAMPLES`. Enable building examples [default: OFF]\n* `BUILD_TESTS`. Enable building tests [default: OFF]\n\nPlease note that if `BUILD_ALL` or `BUILD_EXAMPLES` or `BUILD_TESTS` is turned\nON then both `SOBJECTIZER_BUILD_STATIC` and `SOBJECTIZER_BUILD_SHARED` must be\nturned ON. It means that if `SOBJECTIZER_BUILD_STATIC` or\n`SOBJECTIZER_BUILD_SHARED` is turned OFF then\n`BUILD_ALL`/`BUILD_EXAMPLES`/`BUILD_TESTS` all must be turned OFF.\n\nTo build SObjectizer under Windows by MS Visual Studio 2013 from command line:\n\n```sh\ngit clone https://github.com/stiffstream/sobjectizer\ncd sobjectizer\nmkdir cmake_build\ncd cmake_build\ncmake -DCMAKE_INSTALL_PREFIX=target -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 15 2017\" ../dev\ncmake --build . --config Release\ncmake --build . --config Release --target install\n```\n\nIf it necessary to build examples too, use `BUILD_ALL` in cmake invocation:\n\n```sh\ncmake -DCMAKE_INSTALL_PREFIX=target -DCMAKE_BUILD_TYPE=Release -DBUILD_ALL=ON -G \"Visual Studio 15 2017\" ../dev\n```\n\nSince v.5.5.24 SObjectizer provides sobjectizer-config.cmake files.\nThese files are automatically installed into `\u003ctarget\u003e/lib/cmake/sobjectizer`\nsubfolder. It allows to use SObjectizer via CMake's find_package command.\n\n## Building for Android\n\nBuilding for Android is possible via a rather fresh Android NDK or [CrystaX\nNDK](https://www.crystax.net/android/ndk).\n\n### Building with Android NDK\n\nYou need Android SDK and Android NDK installed in your system. As well as an\nappropriate version of CMake. You have also need properly set environment\nvariables `ANDROID_HOME`, `ANDROID_NDK`. Then you can issue the following\ncommands:\n\n```sh\ngit clone https://github.com/stiffstream/sobjectizer\ncd sobjectizer\nmkdir cmake_build\ncd cmake_build\ncmake -DBUILD_ALL -DCMAKE_INSTALL_PREFIX=target -DCMAKE_BUILD_TYPE=Release \\\n     -DCMAKE_TOOLCHAIN_FILE=${ANDROID_NDK}/build/cmake/android.toolchain.cmake \\\n     -G Ninja \\\n     -DANDROID_ABI=arm64-v8a \\\n     -DANDROID_NDK=${ANDROID_NDK} \\\n     -DANDROID_NATIVE_API_LEVEL=23 \\\n     -DANDROID_TOOLCHAIN=clang \\\n     ../dev\ncmake --build . --config=Release\ncmake --build . --config=Release --target install\n```\n\n### Building with CrystaX NDK\n\nYou need CrystaX NDK v.10.4.0 or higher already installed in your system. CMake\nis used for building SObjectizer:\n\n```sh\ngit clone https://github.com/stiffstream/sobjectizer\ncd sobjectizer\nmkdir cmake_build\ncd cmake_build\nexport NDK=/path/to/the/crystax-ndk\ncmake -DBUILD_ALL -DCMAKE_INSTALL_PREFIX=result -DCMAKE_TOOLCHAIN_FILE=$NDK/cmake/toolchain.cmake -DANDROID_ABI=arm64-v8a ../dev\nmake\nmake test\nmake install\n```\n\n## Using C++ Dependency Managers\n\n### Using via vcpkg\n\nTo use SObjectizer via [vcpkg](https://github.com/Microsoft/vcpkg) it is necessary to do the following steps.\n\nInstall `sobjectizer` package:\n\n```sh\nvcpkg install sobjectizer\n```\n\nAdd the following lines into your CMakeLists.txt file:\n\n```cmake\nfind_package(sobjectizer CONFIG REQUIRED)\ntarget_link_libraries(your_target sobjectizer::SharedLib) # or sobjectizer::StaticLib\n```\n\n### Using via Conan\n\n**NOTE.** Since Feb 2021 new versions of SObjectizer are available via [conan-center](https://conan.io/center/) only.\n\n#### Installing SObjectizer And Adding It To conanfile.txt\n\nTo use SObjectizer via Conan it is necessary to add SObjectizer to\n`conanfile.txt` of your project:\n\n```\n[requires]\nsobjectizer/5.8.0\n```\n\nIt also may be necessary to specify `shared` option for SObjectizer. For example, for build SObjectizer as a static library:\n\n```\n[options]\nsobjectizer:shared=False\n```\n\nInstall dependencies for your project:\n\n```\nconan install SOME_PATH --build=missing\n```\n\n#### Adding SObjectizer To Your CMakeLists.txt\n\n```cmake\n...\ninclude(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)\nconan_basic_setup()\n\n...\ntarget_link_libraries(your_target ${CONAN_LIBS})\n```\n\n# License\n\nSObjectizer is distributed under 3-clause BSD license. For license information\nplease see LICENSE file.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fsobjectizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstiffstream%2Fsobjectizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstiffstream%2Fsobjectizer/lists"}