diff --git a/chronos.nimble b/chronos.nimble index 01117b6b..e063ac35 100644 --- a/chronos.nimble +++ b/chronos.nimble @@ -50,7 +50,7 @@ task examples, "Build examples": # Build book examples for file in listFiles("docs/examples"): if file.endsWith(".nim"): - build "", file + build "--threads:on", file task test, "Run all tests": for args in testArguments: diff --git a/docs/examples/signalling.nim b/docs/examples/signalling.nim new file mode 100644 index 00000000..1d4e932e --- /dev/null +++ b/docs/examples/signalling.nim @@ -0,0 +1,38 @@ +import chronos, chronos/threadsync +import os + +type + Context = object + # Context allocated by `createShared` should contain no garbage-collected + # types! + signal: ThreadSignalPtr + value: int + +proc myThread(ctx: ptr Context) {.thread.} = + echo "Doing some work in a thread" + sleep(3000) + ctx.value = 42 + echo "Done, firing the signal" + discard ctx.signal.fireSync().expect("correctly initialized signal should not fail") + +proc main() {.async.} = + let + signal = ThreadSignalPtr.new().expect("free file descriptor for signal") + context = createShared(Context) + context.signal = signal + + var thread: Thread[ptr Context] + + echo "Starting thread" + createThread(thread, myThread, context) + + await signal.wait() + + echo "Work done: ", context.value + + joinThread(thread) + + signal.close().expect("closing once works") + deallocShared(context) + +waitFor main() diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index f8343670..9bd22f67 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,6 +6,7 @@ - [Core concepts](./concepts.md) - [`async` functions](async_procs.md) - [Errors and exceptions](./error_handling.md) +- [Threads](./threads.md) - [Tips, tricks and best practices](./tips.md) - [Porting code to `chronos`](./porting.md) - [HTTP server middleware](./http_server_middleware.md) diff --git a/docs/src/examples.md b/docs/src/examples.md index 0bcfc74b..2670570d 100644 --- a/docs/src/examples.md +++ b/docs/src/examples.md @@ -8,6 +8,10 @@ Examples are available in the [`docs/examples/`](https://github.com/status-im/ni * [timeoutsimple](https://github.com/status-im/nim-chronos/tree/master/docs/examples/timeoutsimple.nim) - Simple timeouts * [timeoutcomposed](https://github.com/status-im/nim-chronos/tree/master/docs/examples/examples/timeoutcomposed.nim) - Shared timeout of multiple tasks +## Threads + +* [signalling](https://github.com/status-im/nim-chronos/tree/master/docs/examples/signalling.nim) - Cross-thread signalling + ## TCP * [tcpserver](https://github.com/status-im/nim-chronos/tree/master/docs/examples/tcpserver.nim) - Simple TCP/IP v4/v6 echo server diff --git a/docs/src/threads.md b/docs/src/threads.md new file mode 100644 index 00000000..a2859040 --- /dev/null +++ b/docs/src/threads.md @@ -0,0 +1,18 @@ +# Threads + +While the cooperative [`async`](./concepts.md) model offers an efficient model +for dealing with many tasks that often are blocked on I/O, it is not suitable +for long-running computations that would prevent concurrent tasks from progressing. + +Multithreading offers a way to offload heavy computations to be executed in +parallel with the async work, or, in cases where a single event loop gets +overloaded, to manage multiple event loops in parallel. + +For interaction between threads, the `ThreadSignalPtr` type (found in the +(`chronos/threadsync`)(https://github.com/status-im/nim-chronos/blob/master/chronos/threadsync.nim) +module) is used - both to wait for notifications coming from other threads and +to notify other threads of progress from within an async procedure. + +```nim +{{#include ../examples/signalling.nim}} +```