⚠️ This guide has not been actively kept up to date since before Nim 1.0. Many things are still the same, but some things have changed.

Channels

Nim provides channels, used to communicate between threads.

Here is an example with plain threads.

import std/os # for sleep

var
  # create a channel to send/recv strings
  commChan: Channel[string]
  sender: Thread[void]
  recver: Thread[void]

proc sendMsg() =
  sleep(500)
  # send a message in the channel
  commChan.send("Hi")

proc recvMsg() =
  # block on the channel, waiting for output
  let msg: string = commChan.recv()
  echo "Received message: " & msg

# very important: channels must be opened before they can be used
commChan.open()
createThread(sender, sendMsg)
createThread(recver, recvMsg)
joinThreads(sender, recver)

Usually, channels are created as global variables. That means you must follow a certain procedure if you wish to manually allocate shared memory for channels.

The same example, using the higher level spawn:

import threadpool, std/os

var commChan: Channel[string]

proc sendMsg() =
  sleep(500)
  commChan.send("Hi there!")

proc recvMsg() =
  let msg = commChan.recv()
  echo "Received msg: " & msg

commChan.open()
spawn recvMsg()
spawn sendMsg()
sync()

Note that all messages are deep copied when sent.

Channels can be used in a non-blocking way as follows:

while true:
  let tried = commChan.tryRecv()
  if tried.dataAvailable:
    echo tried.msg

When a channel is opened, it can be set with a max number of items:

# create a channel to transfer ints
var chan Channel[int]
# allow max of 10 items in channel
chan.open(10)

The default is set to 0, which means unlimited queue size.

When the channel size is limited, new sends will be blocked if there is not enough space. You can use the trySend function instead, which returns immediately with a bool representing success of the operation.

See the documentation.