For the owlkettle package (a declarative gtk wrapper) in nim I am researching how one could implement multi-threading "properly".
For that I am looking into how one would setup a client-serer architecture generally.
I know nim is able to run multi-threaded when compiled with --threads:on (or on nim 2.0 by default), so this should be possible. This minimal example showcases a mechanism called "channels", but how do I turn this into a more client-server based example where both threads keep going until I stop it?
That just requires a small while-loop on both ends.
The following example is a modification of the one linked above. One "frontend" thread reads in user input from the terminal and sends it to the "backend" thread which can do things with it.
Note that you could also use an object-variant instead of a string (so Channel[YourMessageVariant]
) to allow for sending different kind of messages.
Also as a sidenote, the following example will have 3 threads running:
import std/[os]
proc setupSender(commChan: var Channel[string]): Thread[ptr Channel[string]] =
proc sendMsg(chan: ptr Channel[string]) =
echo "Type in a message to send to the Backend!"
while true:
let terminalInput = readLine(stdin) # This is blocking, so this Thread doesn't run through unnecessary while-loop iterations unlike the receiver thread
echo "Sending message from frontend from thread ", getThreadId(), ": ", terminalInput
while not chan[].trySend(terminalInput):
echo "Try again"
createThread(result, sendMsg, commChan.addr)
proc setupReceiver(commChan: var Channel[string]): Thread[ptr Channel[string]] =
proc recvMsg(chan: ptr Channel[string]) =
while true:
let response: tuple[dataAvailable: bool, msg: string] = chan[].tryRecv()
if response.dataAvailable:
echo "Received message at Backend on Thread: ", getThreadId(), " :", response.msg
sleep(0) # Reduces stress on CPU when idle, increase when higher latency is acceptable for even better idle efficiency
createThread(result, recvMsg, commChan.addr)
proc main() =
var commChan: Channel[string] # A queue of messages send from one thread to another, can have a pre-defined size
commChan.open() # Must be done before using the channel
let senderThread = setupSender(commChan)
let receiverThread = setupReceiver(commChan)
joinThreads(senderThread, receiverThread)
main()