Skip to content

Lifecycle and Execution

Lifecycle and Execution

Configure listeners, protocol options and TLS identity before starting an object. Keep the object and every resource captured by its callbacks alive until shutdown completes. A receive callback’s data view is valid only for the duration of that callback; copy it to retain it.

is_started() and is_stopped() read atomic lifecycle state and can be queried from another thread while the object is alive. Each result is a snapshot; it does not reserve the connection or make direct socket access safe across threads.

Server get_listen_address() and get_listen_port() read synchronized endpoint snapshots during start and close. Direct acceptor() access still follows Asio’s threading rules.

Owned IO pools use one context and one worker per lane. External contexts can have one or multiple threads calling run(). Each external lane uses a strand that serializes its callbacks. A callback can run on a different host thread on its next invocation. Independent lanes can execute concurrently, so shared application state still needs synchronization.

For transport clients and servers:

Operation Contract
stop() from an owner thread Initiate shutdown and wait for completion
request_stop() Schedule shutdown; suitable inside a network callback
wait_stopped() from an owner thread Complete shutdown and report whether waiting was allowed
wait_stopped() from a worker of the involved context/pool Return false with operation_not_supported

For TCP-based endpoints, owner-thread completion includes canceled native I/O, accepted callback captures and session work that still borrows the server. Stopping rejects new user timers, delayed posts and condition waits; an explicit restart reopens them. Already accepted condition callbacks still run during shutdown. Stop application producers before shutdown: immediate posts remain available, so callbacks must not submit work indefinitely. Serialize lifecycle operations such as stop followed by restart. TCP servers, including their HTTP, WebSocket and TLS variants, allow concurrent owner stop waiters. If a callback’s capture or a session destructor reenters stop on the same owner thread during drain, stop() returns without waiting and sets operation_not_supported; wait_stopped() returns false with that error.

Database clients use their own asynchronous close() contract; see database shutdown.

Keep external contexts, their runners and work guards running throughout start, send and shutdown. arknet does not stop the host context. Stop and destroy the network objects first, then release the host work guards and join the runners. Let run() drain queued completion handlers before it returns. io_context::stop() stops dispatching handlers; it does not perform this drain. Keep every context alive until its runners finish, including handlers retaining sessions or strands from another context. Do not destroy an owned IO pool on one of its workers; its destructor terminates in that case.

The standalone arknet::timer starts during construction and has stop(), but no request_stop() or wait_stopped(). Calling its stop() in a callback is nonblocking. An owner thread can call stop() again to drain pending completion handlers while the external context is still running.

Process shutdown

Stop network work and release its owners before returning from main. When a callback releases the last endpoint owner on an owned IO worker, arknet defers pool deletion to a cleanup worker. Process cleanup waits for those owned pools, their callbacks and TLS resources before OpenSSL’s normal global cleanup. The cleanup worker starts when the first owned IO pool is constructed, rather than when a header is included.

For globals, include an arknet IO header before declaring the owning object in each translation unit. This also covers an initially empty shared_ptr assigned from main. A forward-declared or type-erased global owner in another translation unit without that include must be explicitly reset before main returns; its static destruction order cannot be inferred by arknet.

The default Standalone Asio configuration uses native thread storage. If Asio was included first, or the application explicitly selects legacy pthread-key thread storage, keep that configuration consistent across translation units and destroy all owned endpoints and pools before leaving main. External IO runners remain the application’s responsibility.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close