Skip to content

Commit aebcbfe

Browse files
chr-1xnarimiran
authored andcommitted
[backport] documentation: Add channels examples (#13202) [ci skip]
1 parent b68eb1c commit aebcbfe

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

lib/system/channels.nim

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,120 @@
2020
##
2121
## **Note:** Channels cannot be passed between threads. Use globals or pass
2222
## them by `ptr`.
23+
##
24+
## Example
25+
## =======
26+
## The following is a simple example of two different ways to use channels:
27+
## blocking and non-blocking.
28+
##
29+
## .. code-block :: Nim
30+
## # Be sure to compile with --threads:on.
31+
## # The channels and threads modules are part of system and should not be
32+
## # imported.
33+
## import os
34+
##
35+
## # Channels can either be:
36+
## # - declared at the module level, or
37+
## # - passed to procedures by ptr (raw pointer) -- see note on safety.
38+
## #
39+
## # For simplicity, in this example a channel is declared at module scope.
40+
## # Channels are generic, and they include support for passing objects between
41+
## # threads.
42+
## # Note that objects passed through channels will be deeply copied.
43+
## var chan: Channel[string]
44+
##
45+
## # This proc will be run in another thread using the threads module.
46+
## proc firstWorker() =
47+
## chan.send("Hello World!")
48+
##
49+
## # This is another proc to run in a background thread. This proc takes a while
50+
## # to send the message since it sleeps for 2 seconds (or 2000 milliseconds).
51+
## proc secondWorker() =
52+
## sleep(2000)
53+
## chan.send("Another message")
54+
##
55+
## # Initialize the channel.
56+
## chan.open()
57+
##
58+
## # Launch the worker.
59+
## var worker1: Thread[void]
60+
## createThread(worker1, firstWorker)
61+
##
62+
## # Block until the message arrives, then print it out.
63+
## echo chan.recv() # "Hello World!"
64+
##
65+
## # Wait for the thread to exit before moving on to the next example.
66+
## worker1.joinThread()
67+
##
68+
## # Launch the other worker.
69+
## var worker2: Thread[void]
70+
## createThread(worker2, secondWorker)
71+
## # This time, use a non-blocking approach with tryRecv.
72+
## # Since the main thread is not blocked, it could be used to perform other
73+
## # useful work while it waits for data to arrive on the channel.
74+
## while true:
75+
## let tried = chan.tryRecv()
76+
## if tried.dataAvailable:
77+
## echo tried.msg # "Another message"
78+
## break
79+
##
80+
## echo "Pretend I'm doing useful work..."
81+
## # For this example, sleep in order not to flood stdout with the above
82+
## # message.
83+
## sleep(400)
84+
##
85+
## # Wait for the second thread to exit before cleaning up the channel.
86+
## worker2.joinThread()
87+
##
88+
## # Clean up the channel.
89+
## chan.close()
90+
##
91+
## Sample output
92+
## -------------
93+
## The program should output something similar to this, but keep in mind that
94+
## exact results may vary in the real world::
95+
## Hello World!
96+
## Pretend I'm doing useful work...
97+
## Pretend I'm doing useful work...
98+
## Pretend I'm doing useful work...
99+
## Pretend I'm doing useful work...
100+
## Pretend I'm doing useful work...
101+
## Another message
102+
##
103+
## Passing Channels Safely
104+
## ----------------------
105+
## Note that when passing objects to procedures on another thread by pointer
106+
## (for example through a thread's argument), objects created using the default
107+
## allocator will use thread-local, GC-managed memory. Thus it is generally
108+
## safer to store channel objects in global variables (as in the above example),
109+
## in which case they will use a process-wide (thread-safe) shared heap.
110+
##
111+
## However, it is possible to manually allocate shared memory for channels
112+
## using e.g. ``system.allocShared0`` and pass these pointers through thread
113+
## arguments:
114+
##
115+
## .. code-block :: Nim
116+
## proc worker(channel: ptr Channel[string]) =
117+
## let greeting = channel[].recv()
118+
## echo greeting
119+
##
120+
## proc localChannelExample() =
121+
## # Use allocShared0 to allocate some shared-heap memory and zero it.
122+
## # The usual warnings about dealing with raw pointers apply. Exercise caution.
123+
## var channel = cast[ptr Channel[string]](
124+
## allocShared0(sizeof(Channel[string]))
125+
## )
126+
## channel[].open()
127+
## # Create a thread which will receive the channel as an argument.
128+
## var thread: Thread[ptr Channel[string]]
129+
## createThread(thread, worker, channel)
130+
## channel[].send("Hello from the main thread!")
131+
## # Clean up resources.
132+
## thread.joinThread()
133+
## channel[].close()
134+
## deallocShared(channel)
135+
##
136+
## localChannelExample() # "Hello from the main thread!"
23137

24138
when not declared(ThisIsSystem):
25139
{.error: "You must not import this module explicitly".}

0 commit comments

Comments
 (0)