KStateMachine / kstatemachine

KStateMachine is a powerful Kotlin Multiplatform library with clean DSL syntax for creating complex state machines and statecharts driven by Kotlin Coroutines.
https://kstatemachine.github.io/kstatemachine/
Boost Software License 1.0
358 stars 21 forks source link

Clarification of concurrency #95

Closed asomov closed 7 months ago

asomov commented 7 months ago

The documentation clearly states: KStateMachine is designed to work in single thread. Concurrent modification of library classes will lead to race conditions.

Does is also mean that the calls to processEvent() must be done from the same thread ? I understand that creating the state machine with its states, listeners and transitions is single-threaded. But may be processEvent() can be called from different threads ?

nsk90 commented 7 months ago

Hi, the short answer - yes, it can be called from any context (thread).

Details: If you are using StateMachine instance created by createStateMachine/createStateMachineBlocking functions (with CoroutineScope specified), then it is safe to call any suspendable library methods (including processEvent()) on such instance, from any CoroutineContext (driven by any thread), as all those methods switch the CoroutineContext internally to machines one.

But if you create StateMachine instance without coroutines support (by createStdLibStateMachine) then the answer is no, as internal context switching cannot be performed in such case.

See Coroutines section in docs, there was some explanation regarding this behaviour.

Please don't forget that the CoroutineScope that you specify when creating a StateMachine instance sould be driven by single thread. That is actually preserves the guaranties that you have mentioned in coroutines environment.

asomov commented 7 months ago

Thank you the the quick and descriptive answer ! I think it deserves to be in the docs instead of a very short and confusing statement.

nsk90 commented 7 months ago

I have updated the docs, and linked related sections.

asomov commented 7 months ago

@nsk90 may I ask you to add yet another sample to the ones provided inside the project with the way to properly create the Scope ? Please don't forget that the CoroutineScope that you specify when creating a StateMachine instance sould be driven by single thread.

Or the one shown in the docs is the way ? (is the machineScope single threaded there ?)

nsk90 commented 7 months ago
CoroutineScope(newSingleThreadContext("context"))
CoroutineScope(Dispatchers.Main)

here are some samples, I will attach them to the docs.

(is the machineScope single threaded there ?)

yes it is also single threaded, runBlocking implementation creates an event loop on current running thread (it will be used as context thread), if the context is not specified explicitly.