The execution of an application written in a reactive language involves transfer of data and control flow between imperative and reactive abstractions at well-defined points. In a multi-threaded environment, multiple such interactions may execute concurrently, potentially causing data races and event ordering ambiguities. Existing RP languages either disable multi-threading or handle it at the cost of reducing expressiveness or weakening consistency. This paper proposes a model for thread-safe reactive programming (RP) that ensures abort-free strict serializability under concurrency while sacrificing neither expressiveness nor consistency. We also propose an architecture for integrating a corresponding scheduler into the RP language runtime, such that thread-safety is provided łout-of-the-boxž to the applications.We show the feasibility of our proposal by providing and evaluating a ready-to-use implementation integrated into the REScala programming language. The scheduling algorithm is formally proven correct. A thorough empirical evaluation shows that reactive applications build on top of it scale with multiple threads, while the scheduler incurs acceptable performance overhead in a single-threaded configuration. The scalability enabled by our scheduler is roughly on-par with that of hand-crafted application-specific locking and better than the scalability enabled by a scheduler using an off-the-shelf software transactional memory library. 1 We chose REScala, because its API is designed to support different backend runtimes.Thread-Safe Reactive Programming 107:3 with that of hand-crafted application-specific locking, and better while also providing stronger guarantees than a scheduler using an off-the-shelf Software Transactional Memory library. ğ2 introduces RP concepts from the user perspective, ğ6 positions our approach with respect to related work, and ğ7 concludes the paper and discusses areas of future work.
REACTIVE PROGRAMMING IN RESCALAWe introduce (single-threaded) RP from the developer's perspective by implementing an example application in REScala. Our design is inspired by the dining philosophers [Hoare 1985], with philosophers sharing forks around a table. We later introduce concurrency and discuss its effects through multiple threads concurrently executing updates for different philosophers. For flexibility in later examples and benchmarks, the table's SIZE (number of philosophers and forks) is parametric.
The User PerspectiveWe introduce Events, Signals, conversions between them and their imperative interactions.Signals. Philosophers are modelled as Vars of type Phil, initially in state Thinking. 1 cases Phil = { Thinking, Eating } 2 val phils = for (j <− 1 until SIZE) yield Var[Phil](Thinking)A REScala Var is a kind of mutable variable. Like ordinary variables, the value of a Var can be read (through now, e.g., phils(1).now reads the current value of the philosopher with index 1) and overwritten (through set(...), e.g., phils(1).set(Eating)). Unlike ordinary variables, changes of Vars are autom...