diff --git a/doc/usage.md b/doc/usage.md index df103e9f..6b294ce1 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -12,6 +12,12 @@ The `*.capnp` data definition files are consumed by the _libmultiprocess_ code g The `ProxyServer` objects help translate IPC requests from a socket to method calls on a local object. The `ProxyServer` objects are just used internally by the `mp::ServeStream(loop, socket, wrapped_object)` and `mp::ListenConnections(loop, socket, wrapped_object[, max_connections])` functions, and aren't exposed externally. The `ProxyClient` classes are exposed, and returned from the `mp::ConnectStream(loop, socket)` function and meant to be used directly. The classes implement methods described in `.capnp` definitions, and whenever any method is called, a request with the method arguments is sent over the associated IPC connection, and the corresponding `wrapped_object` method on the other end of the connection is called, with the `ProxyClient` method blocking until it returns and forwarding back any return value to the `ProxyClient` method caller. +## Event loop + +Making connections and IPC calls requires an `mp::EventLoop` instance running in its own dedicated thread. The event loop is reference-counted, and `EventLoop::loop()` returns when the last `mp::EventLoopRef` is released. Therefore, any code that needs to use the loop across multiple calls should maintain its own `EventLoopRef`. Connection objects and proxy objects automatically hold a reference for as long as they exist. + +For a typical setup, see [example.cpp](../example/example.cpp). + ## Example A simple interface description can be found at [test/mp/test/foo.capnp](../test/mp/test/foo.capnp), implementation in [test/mp/test/foo.h](../test/mp/test/foo.h), and usage in [test/mp/test/test.cpp](../test/mp/test/test.cpp). diff --git a/example/example.cpp b/example/example.cpp index c6b32f0d..e4d159ab 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ int main(int argc, char** argv) loop.loop(); }); mp::EventLoop* loop = promise.get_future().get(); + mp::EventLoopRef loop_ref{*loop}; auto [printer_init, printer_pid] = Spawn(*loop, argv[0], "mpprinter"); auto [calc_init, calc_pid] = Spawn(*loop, argv[0], "mpcalculator"); @@ -71,6 +73,7 @@ int main(int argc, char** argv) mp::WaitProcess(calc_pid); printer_init.reset(); mp::WaitProcess(printer_pid); + loop_ref.reset(); loop_thread.join(); std::cout << "Bye!" << std::endl; return 0; diff --git a/include/mp/proxy.h b/include/mp/proxy.h index 8d63e9aa..2144b571 100644 --- a/include/mp/proxy.h +++ b/include/mp/proxy.h @@ -44,7 +44,9 @@ inline void CleanupRun(CleanupList& fns) { } } -//! Event loop smart pointer automatically managing m_num_refs. +//! Event loop smart pointer automatically managing m_num_refs. Hold one +//! reference to keep the loop running, once the last reference is released +//! EventLoop::loop() will exit. //! If a lock pointer argument is passed, the specified lock will be used, //! otherwise EventLoop::m_mutex will be locked when needed. class EventLoopRef