Femtos is an experimental structured concurrency library for OCaml 5.x, designed to explore the semantics of composable concurrency using effect handlers.
β οΈ Experimental Research Library Femtos is a research project for understanding structured concurrency semantics and is not intended for production use. For production applications, please use these mature alternatives:
- Picos - Systematic approach to interoperable concurrency
- JaneStreet Await - Production-ready structured concurrency
- Eio - Full-featured effects-based I/O and concurrency
- π Structured Concurrency: Hierarchical task management with automatic cleanup
- β‘ Effect Handlers: Built on OCaml 5.x's native effect system
- π§΅ Multiple Schedulers: FIFO cooperative scheduler and Flock structured scheduler
- π Synchronization Primitives: Ivar (promises), Mvar (channels), and Terminators
- π‘οΈ Exception Safety: Proper exception propagation and resource cleanup
- π Lightweight: Minimal overhead with efficient cooperative multitasking
opam install femtosOr build from source:
git clone https://github.com/kayceesrk/femtos.git
cd femtos
dune build
dune installNote: Femtos is experimental software for research purposes. For production applications, we recommend Picos, JaneStreet Await, or Eio.
open Femtos
let main () =
(* Create a structured scope - all tasks will complete before returning *)
Mux.Flock.finish (fun () ->
(* Spawn concurrent tasks *)
Mux.Flock.async (fun () ->
print_endline "Task 1 running");
Mux.Flock.async (fun () ->
print_endline "Task 2 running");
print_endline "Main task";
"All tasks completed" (* This won't return until all async tasks finish *)
)
let () = Mux.Flock.run main |> print_endlineopen Femtos
let main terminator =
(* Fork a child fiber *)
Mux.Fifo.fork (fun _ ->
print_endline "Child fiber running");
print_endline "Main fiber";
(* Yield control to other fibers *)
Mux.Fifo.yield ();
print_endline "Main fiber continues"
let () = Mux.Fifo.run mainopen Femtos
let main () =
Mux.Flock.finish (fun () ->
let promise = Sync.Ivar.create () in
(* Producer task *)
Mux.Flock.async (fun () ->
Unix.sleepf 0.1;
Sync.Ivar.try_fill promise "Hello from async task!" |> ignore);
(* Consumer task *)
Mux.Flock.async (fun () ->
let result = Sync.Ivar.read promise in (* Blocks until filled *)
print_endline ("Received: " ^ result));
"Communication complete"
)
let () = Mux.Flock.run main |> print_endlineopen Femtos
let main () =
Mux.Flock.finish (fun () ->
let channel = Sync.Mvar.create () in
(* Producer *)
Mux.Flock.async (fun () ->
for i = 1 to 3 do
Sync.Mvar.put channel i;
Printf.printf "Produced: %d\n%!" i
done);
(* Consumer *)
Mux.Flock.async (fun () ->
for _ = 1 to 3 do
let value = Sync.Mvar.take channel in
Printf.printf "Consumed: %d\n%!" value
done);
"Producer-consumer complete"
)
let () = Mux.Flock.run main |> print_endlineFemtos implements structured concurrency through the Flock scheduler:
finish- Creates a scope that waits for all spawned tasksasync- Spawns a task within the current scope- Exception propagation - Any task failure terminates the entire scope
- Automatic cleanup - Resources are cleaned up when scopes end
Mux.Flock.finish (fun () ->
Mux.Flock.async (fun () -> failwith "This will terminate the entire scope");
Mux.Flock.async (fun () -> print_endline "This might not run");
"This won't be reached"
)The FIFO scheduler provides cooperative multitasking:
fork- Creates concurrent fibersyield- Voluntarily gives up control- FIFO scheduling - First-in-first-out execution order
Ivar (Single-assignment variables):
- Write-once, read-many semantics
- Blocking reads until value is available
- Perfect for promises and futures
MVar (Mutable variables):
- Put/take operations with blocking
- Empty β Full state transitions
- Great for producer-consumer patterns
Terminator:
- Coordinates cancellation across multiple tasks
- Used internally by structured concurrency
- Multicore-safe cancellation propagation
Femtos.Trigger- Low-level signaling mechanismFemtos.Sync.Ivar- Single-assignment variables (promises)Femtos.Sync.Mvar- Mutable variables with blockingFemtos.Sync.Terminator- Cancellation coordinationFemtos.Mux.Fifo- FIFO cooperative schedulerFemtos.Mux.Flock- Structured concurrency scheduler
Structured Concurrency:
val Mux.Flock.run : (unit -> 'a) -> 'a
val Mux.Flock.finish : (unit -> 'a) -> 'a
val Mux.Flock.async : (unit -> unit) -> unit
val Mux.Flock.terminate : unit -> 'aCooperative Scheduling:
val Mux.Fifo.run : (Sync.Terminator.t -> unit) -> unit
val Mux.Fifo.fork : (Sync.Terminator.t -> unit) -> unit
val Mux.Fifo.yield : unit -> unitSynchronization:
val Sync.Ivar.create : unit -> 'a t
val Sync.Ivar.try_fill : 'a t -> 'a -> bool
val Sync.Ivar.read : 'a t -> 'a
val Sync.Mvar.create : unit -> 'a t
val Sync.Mvar.put : 'a t -> 'a -> unit
val Sync.Mvar.take : 'a t -> 'aGenerate API documentation with odoc:
dune build @doc
open _build/default/_doc/_html/index.htmlThe repository includes comprehensive examples in the test/ directory:
test_flock.ml- Basic structured concurrency patternstest_flock_cancellation.ml- Advanced cancellation scenariostest_ivar.ml- Promise/future patternstest_mvar.ml- Producer-consumer examplestest_scheduler_integration.ml- Scheduler interoperability
Run tests:
dune exec test/test_femtos.exe
dune exec test/test_flock_cancellation.exe- OCaml 5.3+ (for effect handlers)
- dune 3.17+ (build system)
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure
dune buildpasses - Submit a pull request
MIT License. See LICENSE file for details.
- Structured Concurrency by Nathaniel J. Smith
- Eio - OCaml structured concurrency with IO
- OCaml 5.0 Effects - Official effect handlers documentation
Femtos - Small and light, but structured π¦