ev/thread
creates a new thread and resumes a (copy of a) fiber passed as an argument:
(ev/thread
(fiber/new
(fn []
(print "hi, i am running in a new thread"))))
Additionally, there are three optional arguments.
A second argument specifies a value to resume with.
By default, the function will suspend the current fiber until the thread is complete. To run the thread without waiting for a result, pass a third argument :n
to return immediately.
A supervisor channel that will be notified upon completion can be passed as a fourth argument.
There are also some convenience wrappers around ev/thread
:
ev/do-thread
ev/spawn-thread
They both take a body of Janet code to execute.
ev/do-thread
suspends the current fiber until the thread is complete, returning nil
when done
(ev/do-thread
(print "i am also running in a new thread")
(print "in many cases `ev/do-thread` might be more convenient to use")
(print "compared to `ev/thread`...")
(print "once `ev/do-thread` is called, need to wait for the thread ")
(print "to complete before control is regained"))
In constrast, ev/spawn-thread
returns immediately with nil
.
(ev/spawn-thread
(print "i am also running in a new thread")
(print "in many cases `ev/spawn-thread` might be more convenient to use")
(print "compared to `ev/thread`...")
(print "`ev/spawn-thread` returns immediately unlike `ev/do-thread` so ")
(print "there is no waiting to regain control"))
Implementation Details
ev/thread
is implemented underneath in C via cfun_ev_thread
.
Successful thread creation in cfun_ev_thread
calls either:
janet_ev_threaded_call
orjanet_ev_threaded_await
janet_ev_threaded_await
ends up calling janet_ev_threaded_call
.
janet_ev_threaded_call
arranges for a new thread in one of two ways depending on OS:
CreateThread
for Windowspthread_create
for any other supported OS
Threads in Janet do not share a memory heap and must communicate via message passing using a thread channel.
Create a thread channel using ev/thread-chan
.
# create a thread channel
(def t-chan (ev/thread-chan 10))
Use ev/give
to send a message via a thread channel to a thread.
# sending thread
(ev/do-thread
(def msg "a secret message")
(print "sending: " msg)
(ev/give t-chan msg))
Correspondingly, use ev/take
to get messages sent to the current thread via the thread channel.
# receiving thread
(ev/do-thread
(print "received: " (ev/take t-chan)))
Since threads do not share Janet heaps, all values sent as messages are first marshalled to a byte sequence by the sending thread, and then unmarshalled by the receiving thread. Semantically, messages sent with (ev/give t-chan msg)
are first converted to a buffer, and then unmarshalled by the receiving thread via (ev/take t-chan)
.
Values that cannot be marshalled, including thread values, cannot be sent as messages to other threads, or even as part of a message to another thread.
- The Event Loop
- Official Thread Channel Example
- Communicate Between Two Threads Using a Thread Channel
- Two-way Communication Between Two Threads Using Two Thread Channels 1 2 3
Heavily based on:
- Multithreading page of the Janet web site
- docstrings of various Janet callables
All your errors are belong to the assembler of this document :)