ki/README.md
2020-05-17 13:32:28 -04:00

2.2 KiB

ki

GitHub CI

ki is a lightweight structured-concurrency library inspired by libdill, trio, and golang.org/pkg/context.

The primary abstraction is the scope, which delimits the lifetime of threads forked within it.

-- Create a new scope
scoped :: Context -> (Scope -> IO a) -> IO a

-- Fork a thread within a scope
async :: Scope -> (Context -> IO a) -> IO (Thread a)

-- Should I finish up?
cancelled :: Context -> IO Bool
Ki.scoped context \scope -> do
  -- Fork three worker threads
  Ki.async_ scope worker1
  Ki.async_ scope worker2
  Ki.async_ scope worker3

  -- Block until either:
  --   * They all finish successfully
  --   * One throws an exception
  --   * Someone throws an asynchronous exception to us
  Ki.wait scope

A scope can be hard-cancelled. When the callback provided to scoped returns, all remaining threads within it are killed. By the time scoped itself returns, they're guaranteed to have finished, so hard-cancellation is hierarchical.

A scope can be soft-cancelled, too, but it requires cooperation. A thread can observe whether it's meant to gracefully terminate, but it may never notice, or ignore the suggestion.

Soft-cancellation is also hierarchical. It is observable by all threads forked within a scope, and all threads forked by them, and so on.

There's another abstraction, too: the context. It's not as interesting. Just pass it around everywhere you need to create a new scope or check for cancellation.

ki-mtl is an mtl-compatible shim that passes the context around implicitly in a MonadReader.

type MonadKi r m

scoped :: MonadKi r m => (Scope -> m a) -> m a

async :: MonadKi r m => Scope -> m a -> m (Thread a)

cancelled :: MonadKi r m => m Bool

The implementation is tested for deadlocks, race conditions, and other concurrency anomalies by dejafu, a fantastic unit-testing library for concurrent programs.