diff options
author | Peter Drahoš <drahosp@gmail.com> | 2010-10-01 03:22:32 +0200 |
---|---|---|
committer | Peter Drahoš <drahosp@gmail.com> | 2010-10-01 03:22:32 +0200 |
commit | 89d9c98af1ac352ba4d49d660e61b0853d6e1a86 (patch) | |
tree | 15c56d2ce66b4ab147171c0f674cdb4a435ff13f /docs | |
download | lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.tar.gz lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.tar.bz2 lanes-89d9c98af1ac352ba4d49d660e61b0853d6e1a86.zip |
Import to git
Diffstat (limited to 'docs')
-rw-r--r-- | docs/Lua multithreading choices.graffle | bin | 0 -> 2290 bytes | |||
-rw-r--r-- | docs/Lua multithreading choices.svg | 15 | ||||
-rw-r--r-- | docs/comparison.html | 297 | ||||
-rw-r--r-- | docs/index.html | 951 | ||||
-rw-r--r-- | docs/multi.png | bin | 0 -> 4657 bytes | |||
-rw-r--r-- | docs/performance.ods | bin | 0 -> 66817 bytes |
6 files changed, 1263 insertions, 0 deletions
diff --git a/docs/Lua multithreading choices.graffle b/docs/Lua multithreading choices.graffle new file mode 100644 index 0000000..2bd4cb4 --- /dev/null +++ b/docs/Lua multithreading choices.graffle | |||
Binary files differ | |||
diff --git a/docs/Lua multithreading choices.svg b/docs/Lua multithreading choices.svg new file mode 100644 index 0000000..8a09698 --- /dev/null +++ b/docs/Lua multithreading choices.svg | |||
@@ -0,0 +1,15 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||
3 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xl="http://www.w3.org/1999/xlink" version="1.1" viewBox="0 0 813.60004 566.95" width="813.60004pt" height="566.95pt"><metadata xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:date>2008-07-25 19:33Z</dc:date><!-- Produced by OmniGraffle Professional 4.2.1 --></metadata><defs><filter id="Shadow" filterUnits="userSpaceOnUse"><feGaussianBlur in="SourceAlpha" result="blur" stdDeviation="3.488"/><feOffset in="blur" result="offset" dx="0" dy="4"/><feFlood flood-color="black" flood-opacity=".75" result="flood"/><feComposite in="flood" in2="offset" operator="in"/></filter><font-face font-family="Helvetica" font-size="18" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="555.55554" cap-height="722.22223" ascent="770.01953" descent="-229.98047" font-weight="500"><!--NSCTFontDescriptor <0x7988130> = { | ||
4 | NSFontNameAttribute = Helvetica; | ||
5 | NSFontSizeAttribute = 18; | ||
6 | }--><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><marker orient="auto" overflow="visible" markerUnits="strokeWidth" id="FilledArrow_Marker" viewBox="-1 -4 10 8" markerWidth="10" markerHeight="8" color="black"><g><path d="M 8 0 L 0 -3 L 0 3 Z" fill="currentColor" stroke="currentColor" stroke-width="1"/></g></marker><font-face font-family="Courier" font-size="18" units-per-em="1000" underline-position="-178.22266" underline-thickness="57.617188" slope="0" x-height="444.44446" cap-height="611.11115" ascent="753.90625" descent="-246.09375" font-weight="500"><!--NSCTFontDescriptor <0x79dbbf0> = { | ||
7 | NSFontNameAttribute = Courier; | ||
8 | NSFontSizeAttribute = 18; | ||
9 | }--><font-face-src><font-face-name name="Courier"/></font-face-src></font-face><font-face font-family="Helvetica" font-size="16" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="531.25" cap-height="718.75" ascent="770.01953" descent="-229.98047" font-weight="500"><!--NSCTFontDescriptor <0x79dde00> = { | ||
10 | NSFontNameAttribute = Helvetica; | ||
11 | NSFontSizeAttribute = 16; | ||
12 | }--><font-face-src><font-face-name name="Helvetica"/></font-face-src></font-face><font-face font-family="Times" font-size="24" units-per-em="1000" underline-position="-75.683594" underline-thickness="49.316406" slope="0" x-height="458.33334" cap-height="666.6667" ascent="750" descent="-250" font-weight="500"><!--NSCTFontDescriptor <0x79df960> = { | ||
13 | NSFontNameAttribute = "Times-Roman"; | ||
14 | NSFontSizeAttribute = 24; | ||
15 | }--><font-face-src><font-face-name name="Times-Roman"/></font-face-src></font-face></defs><g stroke="none" stroke-opacity="1" stroke-dasharray="none" fill="none" fill-opacity="1"><title>Canvas 1</title><rect fill="white" width="813.60004" height="566.95"/><g><title>Layer 1</title><g><use xl:href="#id4_Graphic" filter="url(#Shadow)"/><use xl:href="#id2_Graphic" filter="url(#Shadow)"/><use xl:href="#id33_Graphic" filter="url(#Shadow)"/><use xl:href="#id36_Graphic" filter="url(#Shadow)"/></g><g id="id4_Graphic"><path d="M 162.15001 63.999992 L 484.84998 63.999992 C 523.0208 63.999992 554 94.02719 554 131.02499 C 554 168.0228 523.0208 198.04999 484.84998 198.04999 L 162.15001 198.04999 C 123.9792 198.04999 93 168.0228 93 131.02499 C 93 94.02719 123.9792 63.999992 162.15001 63.999992" fill="#ffff51"/><path d="M 162.15001 63.999992 L 484.84998 63.999992 C 523.0208 63.999992 554 94.02719 554 131.02499 C 554 168.0228 523.0208 198.04999 484.84998 198.04999 L 162.15001 198.04999 C 123.9792 198.04999 93 168.0228 93 131.02499 C 93 94.02719 123.9792 63.999992 162.15001 63.999992" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(144.10001 120.024994)" fill="black"><tspan font-family="Helvetica" font-size="18" font-weight="500" x="154.878525" y="18" textLength="49.04297">Lanes</tspan></text></g><line x1="67" y1="508" x2="733.09998" y2="508" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><line x1="67" y1="508" x2="67" y2="68.90001" marker-end="url(#FilledArrow_Marker)" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(613 516)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="118.819336">distributed</tspan></text><text transform="translate(104.9992 516)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="118.819336">shared data</tspan></text><text transform="translate(323.5 516)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="140.42285">isolated data</tspan></text><text transform="translate(21.501301 355) rotate(-90)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="108.01758">coroutines</tspan></text><text transform="translate(21.501297 187.5) rotate(-90)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="108.01758">OS threads</tspan></text><g id="id2_Graphic"><ellipse cx="164.4995" cy="312.5" rx="71.49962" ry="67.025116" fill="white"/><ellipse cx="164.4995" cy="312.5" rx="71.49962" ry="67.025116" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(112.299896 293.50003)" fill="black"><tspan font-family="Helvetica" font-size="16" font-weight="500" x="38.85194" y="15" textLength="26.695312">Lua</tspan><tspan font-family="Helvetica" font-size="16" font-weight="500" x="15.28944" y="34" textLength="73.820312">coroutines</tspan></text></g><text transform="translate(21.501301 504) rotate(-90)" fill="black"><tspan font-family="Courier" font-size="18" font-weight="500" x="0" y="18" textLength="97.21582">core mods</tspan></text><g id="id33_Graphic"><ellipse cx="164.49921" cy="441.975" rx="71.49961" ry="67.02514" fill="#ff7695"/><ellipse cx="164.49921" cy="441.975" rx="71.49961" ry="67.02514" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(112.2996 432.47504)" fill="black"><tspan font-family="Helvetica" font-size="16" font-weight="500" x="13.504284" y="15" textLength="77.390625">LuaThread</tspan></text></g><text transform="translate(518 26)" fill="black"><tspan font-family="Times" font-size="24" font-weight="500" x="0" y="23" textLength="262.58203">Lua multithreading choices</tspan></text><g id="id36_Graphic"><path d="M 345.15002 245.475 L 667.84998 245.475 C 706.0208 245.475 737 275.5022 737 312.5 C 737 349.4978 706.0208 379.525 667.84998 379.525 L 345.15002 379.525 C 306.97919 379.525 276 349.4978 276 312.5 C 276 275.5022 306.97919 245.475 345.15002 245.475" fill="#69b1ff"/><path d="M 345.15002 245.475 L 667.84998 245.475 C 706.0208 245.475 737 275.5022 737 312.5 C 737 349.4978 706.0208 379.525 667.84998 379.525 L 345.15002 379.525 C 306.97919 379.525 276 349.4978 276 312.5 C 276 275.5022 306.97919 245.475 345.15002 245.475" stroke="black" stroke-linecap="round" stroke-linejoin="round" stroke-width="1"/><text transform="translate(327.1 301.5)" fill="black"><tspan font-family="Helvetica" font-size="18" font-weight="500" x="119.8629" y="18" textLength="119.07422">ConcurrentLua</tspan></text></g></g></g></svg> | ||
diff --git a/docs/comparison.html b/docs/comparison.html new file mode 100644 index 0000000..84ef9ca --- /dev/null +++ b/docs/comparison.html | |||
@@ -0,0 +1,297 @@ | |||
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
2 | <!-- | ||
3 | Comparison of Lua Lanes with other approaches | ||
4 | --> | ||
5 | |||
6 | <html> | ||
7 | <head> | ||
8 | <meta name="description" content="Lua Lanes - Comparison" /> | ||
9 | <meta name="keywords" content="Lua, Library, Multithreading, Threads, Rocks" /> | ||
10 | |||
11 | <title>Lua Lanes - Comparison</title> | ||
12 | </head> | ||
13 | |||
14 | <body> | ||
15 | |||
16 | <!-- comparisons +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
17 | <hr/> | ||
18 | <h2 id="comparisons">Comparisons to other threading kits</h2> | ||
19 | |||
20 | <p> | ||
21 | A short comparison of Lanes with other existing Lua multithreading kits. | ||
22 | </p> | ||
23 | |||
24 | <table><tr><td width=40> | ||
25 | <td bgcolor="#ffffe0"> | ||
26 | <pre> | ||
27 | ============= | ||
28 | Lua Lanes | ||
29 | ============= | ||
30 | |||
31 | With the introduction of Lindas (Jun-2008), Lua Lanes simplifies its API while | ||
32 | simultaneously adding more power and speed. | ||
33 | |||
34 | Pros: | ||
35 | - regular Lua 5.1 module | ||
36 | - completely separate Lua states, one per OS thread | ||
37 | - message passing, or shared data using Lindas | ||
38 | - no application level locking, ever | ||
39 | - scales well, up to 1000's of threads | ||
40 | - priorities (-2..+2) for launched threads | ||
41 | - threads are cancellable (with complete cleanup) | ||
42 | - timeouts on all pending operations | ||
43 | - thread contents are given as regular Lua functions; syntax checked early on, | ||
44 | syntax highlighting works | ||
45 | - standard libraries opened to subthreads can be granually selected | ||
46 | - fast stack-to-stack copies, via hidden "keeper states". No serialization needed. | ||
47 | - protects calls to 'require', allowing wide compatibility with existing | ||
48 | modules (and all, with minor changes) | ||
49 | |||
50 | Cons: | ||
51 | - requires OS threads | ||
52 | - not utilizing network parallelism (all threads on one CPU) | ||
53 | |||
54 | Sample: | ||
55 | << | ||
56 | require "lanes" | ||
57 | |||
58 | local function calculate(a,b,c) | ||
59 | if not a then | ||
60 | error "sample error; propagated to main lane when reading results" | ||
61 | end | ||
62 | return a+b+c | ||
63 | end | ||
64 | |||
65 | local h1= lanes.new(calculate)(1,2,3) | ||
66 | local h2= lanes.new(calculate)(10,20,30) | ||
67 | local h3= lanes.new(calculate)(100,200,300) | ||
68 | |||
69 | print( h1[1], h2[1], h3[1] ) -- pends for the results, or propagates error | ||
70 | << | ||
71 | |||
72 | |||
73 | ================== | ||
74 | Lua coroutines (by Lua authors) | ||
75 | ================== | ||
76 | |||
77 | <A HREF="http://www.lua.org/manual/5.1/manual.html#2.11">http://www.lua.org/manual/5.1/manual.html#2.11</A> | ||
78 | <A HREF="http://lua-users.org/wiki/CoroutinesTutorial">http://lua-users.org/wiki/CoroutinesTutorial</A> | ||
79 | |||
80 | Lua coroutines is an integral part of Lua 5 itself. It is listed here, since | ||
81 | it should be the _first_ multitasking mechanism to consider. It can also be | ||
82 | used together with Lanes, or the other mechanisms listed below. | ||
83 | |||
84 | Coroutines are very usable in provider/consumer situations, allowing you to | ||
85 | queue Lua functions on an as-needed dataflow basis with each other. | ||
86 | |||
87 | Pros: | ||
88 | - works with plain Lua (no extensions) | ||
89 | - works on any platform | ||
90 | - lightweight (no OS level threading or locking involved) | ||
91 | |||
92 | Cons: | ||
93 | - co-operative, meaning your code will need to decide, who gets to run | ||
94 | - does not utilize multiple CPUs/cores | ||
95 | |||
96 | Sample: | ||
97 | |||
98 | ..TBD: sample code doing the "child" "parent" output here (see below).. | ||
99 | |||
100 | |||
101 | ============= | ||
102 | LuaThread (by Diego Nehab) | ||
103 | ============= | ||
104 | |||
105 | <A HREF="http://www.cs.princeton.edu/~diego/professional/luathread/">http://www.cs.princeton.edu/~diego/professional/luathread/</A> | ||
106 | |||
107 | LuaThread provides thread creation, mutexes, condition variables, and inter- | ||
108 | thread queues to the Lua scripts. It takes a C-kind of approach, where Lua | ||
109 | globals are shared by the threads running, and need therefore to be guarded | ||
110 | against multithreading conflicts. | ||
111 | |||
112 | Whether this is exactly what you want, or whether a more loosely implemented | ||
113 | multithreading (s.a. Lanes) would be better, is up to you. One can argue that | ||
114 | a loose implementation is easier for the developer, since no application level | ||
115 | lockings need to be considered. | ||
116 | |||
117 | Pros: | ||
118 | - no marshalling overhead, since threads share the same Lua state | ||
119 | |||
120 | Cons: | ||
121 | - requires a modified Lua core | ||
122 | - application level locking required | ||
123 | |||
124 | Sample: | ||
125 | << | ||
126 | local function flood(output, word) | ||
127 | while 1 do | ||
128 | output:lock() | ||
129 | io.write(word, ", ") | ||
130 | output:unlock() | ||
131 | end | ||
132 | end | ||
133 | |||
134 | local output = thread.newmutex() | ||
135 | thread.newthread(flood, {output, "child"}) | ||
136 | flood(output, "parent") | ||
137 | << | ||
138 | |||
139 | |||
140 | ============= | ||
141 | Lua Rings (by Roberto Ierusalimschy & Tomás Guisasola) | ||
142 | ============= | ||
143 | |||
144 | <A HREF="http://www.keplerproject.org/rings/">http://www.keplerproject.org/rings/</A> | ||
145 | |||
146 | ".. library which provides a way to create new Lua states from within Lua. | ||
147 | It also offers a simple way to communicate between the creator (master) and | ||
148 | the created (slave) states." | ||
149 | |||
150 | ".. master can execute code in any of its slaves but each slave only has | ||
151 | access to its master (or its own slaves)." | ||
152 | |||
153 | Rings offers separate Lua states, but no multithreading. This makes it simple, | ||
154 | but it won't use more than one CPU core. Other differences include: | ||
155 | |||
156 | - opens all Lua standard libraries for subthreads | ||
157 | (Lanes opens the needed ones) | ||
158 | |||
159 | - marshalls numbers, strings, booleans, userdata | ||
160 | (Lanes marshalls also non-cyclic tables) | ||
161 | |||
162 | - "remotedostring" allows executing code in the master state | ||
163 | (Lanes does _not_ allow subthreads to trouble/modify master automatically, | ||
164 | to allow effective sandboxing. The same can be achieved by sending code | ||
165 | between the threads, but master needs to explicitly allow this = receive | ||
166 | a function and execute it) | ||
167 | |||
168 | - offers "Stable, a very simple API to manage a shared table at the master | ||
169 | state" | ||
170 | (Lanes 2008 offers keeper tables) | ||
171 | |||
172 | Pros: | ||
173 | - "offers Stable, a very simple API to manage a shared table at the master | ||
174 | state" | ||
175 | |||
176 | Cons: | ||
177 | - thread contents defined as strings, not Lua source as such; does not | ||
178 | give syntax check at file parsing, does not allow syntax highlight | ||
179 | |||
180 | Sample: | ||
181 | << | ||
182 | require"rings" | ||
183 | S = rings.new () | ||
184 | |||
185 | data = { 12, 13, 14, } | ||
186 | print (S:dostring ([[ | ||
187 | aux = {} | ||
188 | for i, v in ipairs (arg) do | ||
189 | table.insert (aux, 1, v) | ||
190 | end | ||
191 | return unpack (aux)]], unpack (data))) -- true, 14, 13, 12 | ||
192 | |||
193 | S:close () | ||
194 | << | ||
195 | |||
196 | |||
197 | ========================== | ||
198 | Helper Threads Toolkit (by Javier Guerra G.) | ||
199 | ========================== | ||
200 | |||
201 | <A HREF="http://luaforge.net/projects/helper-threads/">http://luaforge.net/projects/helper-threads/</A> | ||
202 | |||
203 | "Provides a consistent framework to write non-blocking C libraries, with a Lua | ||
204 | interface for starting tasks and managing the Futures, Queues and Threads." | ||
205 | |||
206 | This seems like a companion of the "occasional threading" model (see below); | ||
207 | Lua side is kept clear of multithreading, while C side can be "spawn" off to | ||
208 | do things on the background. | ||
209 | |||
210 | Pros: | ||
211 | - provides an "update" mechanism, allowing the (C) thread and controlling | ||
212 | Lua to interact during execution of the thread | ||
213 | - ... | ||
214 | |||
215 | Cons: | ||
216 | - thread is "only for C code and it can't touch or access the Lua state", | ||
217 | in other words there is no Lua-side multithreading concept (by design) | ||
218 | |||
219 | |||
220 | ======================== | ||
221 | Occasional threading (by Russ Cox) | ||
222 | ======================== | ||
223 | |||
224 | <A HREF="http://lua-users.org/lists/lua-l/2006-11/msg00368.html">http://lua-users.org/lists/lua-l/2006-11/msg00368.html</A> | ||
225 | |||
226 | ".. able to have certain C calls run in parallel with the [Lua] VM, but | ||
227 | otherwise keep the VM single-threaded." | ||
228 | |||
229 | That pretty much says it all. | ||
230 | |||
231 | Pros: | ||
232 | - simple, yet providing for the "occasional" need to run really multithreaded | ||
233 | - can be made into a loadable module (says the message) | ||
234 | |||
235 | Cons: | ||
236 | - only for occasional usage, the programming paradigm is still essentially | ||
237 | singlethreaded (by definition) | ||
238 | - not a real project, just a message on the Lua list (but a good one!) | ||
239 | |||
240 | |||
241 | ================= | ||
242 | ConcurrentLua | ||
243 | ================= | ||
244 | |||
245 | <A TARGET="_blank" HREF="http://concurrentlua.luaforge.net/index.html" | ||
246 | >http://concurrentlua.luaforge.net/index.html</A> | ||
247 | |||
248 | ConcurrentLua is based on the Lua model for concurrency, namely coroutines, and | ||
249 | extends this model by providing message-passing primitives. | ||
250 | |||
251 | ".. implementation of the share-nothing asynchronous message-passing model" | ||
252 | |||
253 | ".. process can check its mailbox for new messages at any time, and if there | ||
254 | are any, they can be read in the order of arrival." | ||
255 | |||
256 | ".. processes in the system are implemented with Lua coroutines" | ||
257 | |||
258 | ".. still based on the cooperative multithreading model that Lua uses" | ||
259 | |||
260 | Recent, released on 21 June 2008. | ||
261 | |||
262 | Pros: | ||
263 | - From ground up designed for distributed computing (multiple computers, | ||
264 | not only CPU cores) | ||
265 | - Does not require a pre-emptive operating system | ||
266 | |||
267 | Cons: | ||
268 | - Serialization must degrade raw performance in one-computer scenarios | ||
269 | (vs. stack-to-stack copying ala Lanes) | ||
270 | - Depends on LuaSocket and Copas modules. | ||
271 | - Each thread has a single mailbox tied to it (vs. separating threads and | ||
272 | connection resources) | ||
273 | |||
274 | </pre> | ||
275 | </td></tr></table> | ||
276 | |||
277 | |||
278 | <!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
279 | <hr/> | ||
280 | |||
281 | <p>For feedback, questions and suggestions: | ||
282 | <UL> | ||
283 | <li><A HREF="http://luaforge.net/projects/lanes">Lanes @ LuaForge</A></li> | ||
284 | <li><A HREF="mailto:akauppi@gmail.com">the author</A></li> | ||
285 | </UL> | ||
286 | </p> | ||
287 | |||
288 | <!-- | ||
289 | <font size="-1"> | ||
290 | <p> | ||
291 | 1) ... | ||
292 | </p> | ||
293 | </font> | ||
294 | --> | ||
295 | |||
296 | </body> | ||
297 | </html> | ||
diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..956e691 --- /dev/null +++ b/docs/index.html | |||
@@ -0,0 +1,951 @@ | |||
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
2 | <!-- | ||
3 | Documentation for Lua Lanes | ||
4 | --> | ||
5 | |||
6 | <html> | ||
7 | <head> | ||
8 | <meta name="description" content="Lua Lanes - multithreading in Lua" /> | ||
9 | <meta name="keywords" content="Lua, Library, Multithreading, Threads, Rocks" /> | ||
10 | |||
11 | <title>Lua Lanes - multithreading in Lua</title> | ||
12 | </head> | ||
13 | |||
14 | <body> | ||
15 | <div class="header"> | ||
16 | <hr /> | ||
17 | |||
18 | <center> | ||
19 | <table summary="Lua logo"> | ||
20 | <tbody> | ||
21 | <tr> | ||
22 | <td align="center"> | ||
23 | <a href="http://www.lua.org"> | ||
24 | <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> | ||
25 | <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> | ||
26 | <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> | ||
27 | <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> | ||
28 | <img src="http://akauppi.googlepages.com/multi.png" alt="Lua" align="middle" border="0" height="120" width="128" /> | ||
29 | </a></td> | ||
30 | </tr> | ||
31 | <tr> | ||
32 | <td align="center" valign="top"><h1>Lua Lanes - multithreading in Lua</h1> | ||
33 | </td> | ||
34 | </tr> | ||
35 | </tbody> | ||
36 | </table> | ||
37 | |||
38 | <p class="bar"> | ||
39 | <a href="#description">Description</a> · | ||
40 | <a href="#systems">Supported systems</a> · | ||
41 | <a href="#installing">Building and Installing</a> | ||
42 | </p><p class="bar"> | ||
43 | <a href="#creation">Creation</a> · | ||
44 | <a href="#status">Status</a> · | ||
45 | <a href="#results">Results and errors</a> | ||
46 | </p><p class="bar"> | ||
47 | <a href="#cancelling">Cancelling</a> · | ||
48 | <a href="#finalizers">Finalizers</a> · | ||
49 | <a href="#lindas">Lindas</a> · | ||
50 | <a href="#timers">Timers</a> · | ||
51 | <a href="#locks">Locks etc.</a> | ||
52 | </p><p class="bar"> | ||
53 | <a href="#other">Other issues</a> · | ||
54 | <a href="#changes">Change log</a> | ||
55 | <!-- ... --> | ||
56 | |||
57 | <p><br/><font size="-1"><i>Copyright © 2007-08 Asko Kauppi. All rights reserved.</i> | ||
58 | <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1. | ||
59 | </p><p>This document was revised on 23-Jan-09, and applies to version 2.0.3. | ||
60 | </font></p> | ||
61 | |||
62 | </center> | ||
63 | </div> | ||
64 | |||
65 | |||
66 | <!-- description +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
67 | <hr/> | ||
68 | <h2 id="description">Description</h2> | ||
69 | |||
70 | <p>Lua Lanes is a Lua extension library providing | ||
71 | the possibility to run multiple Lua states in parallel. It is intended to | ||
72 | be used for optimizing performance on multicore CPU's and to study ways to make Lua programs naturally parallel to begin with. | ||
73 | </p><p> | ||
74 | Lanes is included into your software by the regular | ||
75 | <tt>require "lanes"</tt> method. No C side programming is needed; all APIs are Lua side, and most existing extension modules should | ||
76 | work seamlessly together with the multiple lanes. | ||
77 | </p><p> | ||
78 | See <A HREF="comparison.html">comparison</A> of Lua Lanes with other Lua multithreading solutions. | ||
79 | </p><p> | ||
80 | <h3>Features:</h3> | ||
81 | |||
82 | <ul> | ||
83 | <li>Lanes have separated data, by default. Shared data is possible with Linda objects. | ||
84 | </li> | ||
85 | <li>Communications is separate of threads, using Linda objects. | ||
86 | </li> | ||
87 | <li>Data passing uses fast inter-state copies (no serialization required)</li> | ||
88 | </li> | ||
89 | <li>"Deep userdata" concept, for sharing userdata over multiple lanes | ||
90 | </li> | ||
91 | <li>Millisecond level timers, integrated with the Linda system. | ||
92 | </li> | ||
93 | <li>Threads can be given priorities -2..+2 (default is 0). | ||
94 | </li> | ||
95 | <li>Lanes are cancellable, with proper cleanup. | ||
96 | </li> | ||
97 | <li>No application level locking - ever! | ||
98 | </li> | ||
99 | </ul> | ||
100 | |||
101 | |||
102 | <h3>Limitations:</h3> | ||
103 | |||
104 | <ul><li>coroutines are not passed between states | ||
105 | </li> | ||
106 | <li>sharing full userdata between states needs special C side | ||
107 | preparations (-> <A HREF="#deep_userdata">deep userdata</A>) | ||
108 | </li> | ||
109 | <li>network level parallelism not included | ||
110 | </li> | ||
111 | </ul> | ||
112 | </p> | ||
113 | |||
114 | |||
115 | <!-- systems +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
116 | <hr/> | ||
117 | <h2 id="systems">Supported systems</h2> | ||
118 | |||
119 | <p>Lua Lanes supports the following operating systems: | ||
120 | |||
121 | <ul> | ||
122 | <li>Mac OS X PowerPC / Intel (10.4 and later)</li> | ||
123 | <li>Linux x86</li> | ||
124 | <li>Windows 2000/XP and later <font size="-1">(MinGW or Visual C++ 2005/2008)</font></li> | ||
125 | <!-- | ||
126 | Other OS'es here once people help test them. (and the tester's name) | ||
127 | |||
128 | Win64, BSD, Linux x64, Linux embedded, QNX, Solaris, ... | ||
129 | --> | ||
130 | </ul> | ||
131 | |||
132 | <p>The underlying threading code can be compiled either towards Win32 API | ||
133 | or <a TARGET="_blank" HREF="http://en.wikipedia.org/wiki/POSIX_Threads">Pthreads</a>. Unfortunately, thread prioritation under Pthreads is a JOKE, | ||
134 | requiring OS specific tweaks and guessing undocumented behaviour. Other | ||
135 | features should be portable to any modern platform. | ||
136 | </p> | ||
137 | </p> | ||
138 | |||
139 | |||
140 | <!-- installing +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
141 | <hr/> | ||
142 | <h2 id="installing">Building and Installing</h2> | ||
143 | |||
144 | <p>Lua Lanes is built simply by <tt>make</tt> on the supported platforms | ||
145 | (<tt>make-vc</tt> for Visual C++). See <tt>README</tt> for system specific | ||
146 | details and limitations. | ||
147 | </p> | ||
148 | |||
149 | <p>To install Lanes, all you need are the <tt>lanes.lua</tt> and <tt>lua51-lanes.so|dll</tt> | ||
150 | files to be reachable by Lua (see LUA_PATH, LUA_CPATH). | ||
151 | |||
152 | Or use <A HREF="http://www.luarocks.org" TARGET="_blank">Lua Rocks</A> package management. | ||
153 | </p> | ||
154 | |||
155 | <pre> | ||
156 | > luarocks search lanes | ||
157 | ... output listing Lua Lanes is there ... | ||
158 | |||
159 | > luarocks install lanes | ||
160 | ... output ... | ||
161 | </pre> | ||
162 | |||
163 | |||
164 | <!-- launching +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
165 | <hr/> | ||
166 | <h2 id="creation">Creation</h2> | ||
167 | |||
168 | <p>The following sample shows preparing a function for parallel calling, and | ||
169 | calling it with varying arguments. Each of the two results is calculated in | ||
170 | a separate OS thread, parallel to the calling one. Reading the results | ||
171 | joins the threads, waiting for any results not already there. | ||
172 | </p> | ||
173 | |||
174 | <table border=1 bgcolor="#FFFFE0" width=500><tr><td> | ||
175 | <pre> | ||
176 | require "lanes" | ||
177 | |||
178 | f= lanes.gen( function(n) return 2*n end ) | ||
179 | a= f(1) | ||
180 | b= f(2) | ||
181 | |||
182 | print( a[1], b[1] ) -- 2 4 | ||
183 | </pre> | ||
184 | </table> | ||
185 | |||
186 | <p> | ||
187 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
188 | <code>func= lanes.gen( [libs_str | opt_tbl [, ...],] lane_func ) | ||
189 | <br/><br/> | ||
190 | lane_h= func( ... )</code> | ||
191 | </table> | ||
192 | </p> | ||
193 | </p><p> | ||
194 | The function returned by <tt>lanes.gen()</tt> is a "generator" for | ||
195 | launching any number of lanes. They will share code, options, initial globals, | ||
196 | but the particular arguments may vary. Only calling the generator function | ||
197 | actually launches a lane, and provides a handle for controlling it. | ||
198 | <!-- | ||
199 | </p> | ||
200 | <p>This prepares <tt>lane_func</tt> to be called in parallel. It does not yet start | ||
201 | anything, but merely returns a <i>generator function</i> that can be called | ||
202 | any number of times, with varying parameters. Each call will spawn a new lane. | ||
203 | --> | ||
204 | </p><p> | ||
205 | Lanes automatically copies upvalues over to the new lanes, so you | ||
206 | need not wrap all the required elements into one 'wrapper' function. If | ||
207 | <tt>lane_func</tt> uses some local values, or local functions, they will be there | ||
208 | also in the new lanes. | ||
209 | </p><p> | ||
210 | <code>libs_str</code> defines the standard libraries made available to the | ||
211 | new Lua state: | ||
212 | <table> | ||
213 | <tr><td/><td>(nothing)</td><td>no standard libraries (default)</td></tr> | ||
214 | <tr><td width=40><td><tt>"base"</tt> or <tt>""</tt></td> | ||
215 | <td>root level names, <tt>print</tt>, <tt>assert</tt>, <tt>unpack</tt> etc.</td></tr> | ||
216 | <tr><td/><td><tt>"coroutine"</tt></td><td><tt>coroutine.*</tt> namespace <font size="-1">(part of base in Lua 5.1)</font></td></tr> | ||
217 | <tr><td/><td><tt>"debug"</tt></td><td><tt>debug.*</tt> namespace</td></tr> | ||
218 | <tr><td/><td><tt>"io"</tt></td><td><tt>io.*</tt> namespace</td></tr> | ||
219 | <tr><td/><td><tt>"math"</tt></td><td><tt>math.*</tt> namespace</td></tr> | ||
220 | <tr><td/><td><tt>"os"</tt></td><td><tt>os.*</tt> namespace</td></tr> | ||
221 | <tr><td/><td><tt>"package"</tt></td><td><tt>package.*</tt> namespace and <tt>require</tt></td></tr> | ||
222 | <tr><td/><td><tt>"string"</tt></td><td><tt>string.*</tt> namespace</td></tr> | ||
223 | <tr><td/><td><tt>"table"</tt></td><td><tt>table.*</tt> namespace</td></tr> | ||
224 | <br/> | ||
225 | <tr><td/><td><tt>"*"</tt></td><td>all standard libraries</td></tr> | ||
226 | </table> | ||
227 | |||
228 | </p><p> | ||
229 | Initializing the standard libs takes a bit of time at each lane invocation. | ||
230 | This is the main reason why "no libraries" is the default. | ||
231 | </p><p> | ||
232 | |||
233 | <code>opt_tbl</code> is a collection of named options to control the way | ||
234 | lanes are run: | ||
235 | </p><p> | ||
236 | <table> | ||
237 | <tr valign=top><td/><td> | ||
238 | <code>.cancelstep</code> <br/><nobr>N / true</nobr></td> | ||
239 | <td> | ||
240 | By default, lanes are only cancellable when they enter a pending | ||
241 | <tt>:receive()</tt> or <tt>:send()</tt> call. | ||
242 | With this option, one can set cancellation check to occur every <tt>N</tt> | ||
243 | Lua statements. The value <tt>true</tt> uses a default value (100). | ||
244 | </td></tr> | ||
245 | |||
246 | <tr valign=top><td/><td> | ||
247 | <code>.globals</code> <br/>globals_tbl</td> | ||
248 | <td> | ||
249 | Sets the globals table for the launched threads. This can be used for giving | ||
250 | them constants. | ||
251 | </p><p> | ||
252 | The global values of different lanes are in no manner connected; | ||
253 | modifying one will only affect the particular lane. | ||
254 | </td></tr> | ||
255 | |||
256 | <tr valign=top><td width=40><td> | ||
257 | <code>.priority</code> <br/><nobr>-2..+2</nobr></td> | ||
258 | <td>The priority of lanes generated. -2 is lowest, +2 is highest. | ||
259 | <p> | ||
260 | Implementation and dependability of priorities varies | ||
261 | by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. | ||
262 | </td></tr> | ||
263 | </table> | ||
264 | |||
265 | </p> | ||
266 | |||
267 | <h3>Free running lanes</h3> | ||
268 | |||
269 | <p> | ||
270 | The lane handles are allowed to be 'let loose'; in other words you may execute | ||
271 | a lane simply by: | ||
272 | |||
273 | <pre> | ||
274 | lanes.gen( function() ... end ) () | ||
275 | </pre> | ||
276 | |||
277 | Normally, this kind of lanes will be in an eternal loop handling messages. | ||
278 | Since the lane handle is gone, | ||
279 | there is no way to control such a lane from the outside, nor read its potential | ||
280 | return values. Then again, such a lane does not even normally return. | ||
281 | </p> | ||
282 | |||
283 | |||
284 | <!-- status +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
285 | <hr/> | ||
286 | <h2 id="status">Status</h2> | ||
287 | |||
288 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
289 | <code>str= lane_h.status</code> | ||
290 | </table> | ||
291 | |||
292 | <p>The current execution state of a lane can be read via its <tt>status</tt> | ||
293 | member, providing one of these values: <sup>(<a href="#2">2</a></sup> | ||
294 | |||
295 | <table> | ||
296 | <tr><td width=40><td><tt>"pending"</tt></td><td>not started, yet</td></tr> | ||
297 | <tr><td/><td><tt>"running"</tt></td><td>running</td></tr> | ||
298 | <tr><td/><td><tt>"waiting"</tt></td><td>waiting at a Linda <tt>:receive()</tt> or <tt>:send()</tt></td></tr> | ||
299 | <tr><td/><td><tt>"done"</tt></td><td>finished executing (results are ready)</td></tr> | ||
300 | <tr><td/><td><tt>"error"</tt></td><td>met an error (reading results will propagate it)</td></tr> | ||
301 | <tr><td/><td><tt>"cancelled"</tt></td><td>received cancellation and finished itself</td></tr> | ||
302 | </table> | ||
303 | </p><p> | ||
304 | This is similar to <tt>coroutine.status</tt>, which has: <tt>"running"</tt> / | ||
305 | <tt>"suspended"</tt> / <tt>"normal"</tt> / <tt>"dead"</tt>. Not using the | ||
306 | exact same names is intentional. | ||
307 | </p> | ||
308 | |||
309 | |||
310 | <!-- results +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
311 | <hr/> | ||
312 | <h2 id="results">Results and errors</h2> | ||
313 | |||
314 | <p>A lane can be waited upon by simply reading its results. This can be done | ||
315 | in two ways. | ||
316 | </p><p> | ||
317 | |||
318 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
319 | <code>[val]= lane_h[1]</code> | ||
320 | </table> | ||
321 | <p> | ||
322 | Makes sure lane has finished, and gives its first (maybe only) return value. | ||
323 | Other return values will be available in other <tt>lane_h</tt> indices. | ||
324 | </p><p> | ||
325 | If the lane ended in an error, it is propagated to master state at this place. | ||
326 | </p> | ||
327 | |||
328 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
329 | <code>[...]|[nil,err,stack_tbl]= lane_h:join( [timeout_secs] )</code> | ||
330 | </table> | ||
331 | <p> | ||
332 | Waits until the lane finishes, or <tt>timeout</tt> seconds have passed. | ||
333 | Returns <tt>nil</tt> on timeout, <tt>nil,err,stack_tbl</tt> if the lane hit an error, | ||
334 | or the return values of the lane. Unlike in reading the results in table | ||
335 | fashion, errors are not propagated. | ||
336 | </p><p> | ||
337 | <tt>stack_tbl</tt> is an array of "<filename>:<line>" strings, | ||
338 | describing where the error was thrown. Use <tt>table.concat()</tt> to format | ||
339 | it to your liking (or just ignore it). | ||
340 | </p><p> | ||
341 | If you use <tt>:join</tt>, make sure your lane main function returns | ||
342 | a non-nil value so you can tell timeout and error cases apart from succesful | ||
343 | return (using the <tt>.status</tt> property may be risky, since it might change | ||
344 | between a timed out join and the moment you read it). | ||
345 | </p><p> | ||
346 | |||
347 | <table border=1 bgcolor="#FFFFE0" width=500><tr><td> | ||
348 | <pre> | ||
349 | require "lanes" | ||
350 | |||
351 | f= lanes.gen( function() error "!!!" end ) | ||
352 | a= f(1) | ||
353 | |||
354 | --print( a[1] ) -- propagates error | ||
355 | |||
356 | v,err= a:join() -- no propagation | ||
357 | if v==nil then | ||
358 | error( "'a' faced error"..tostring(err) ) -- manual propagation | ||
359 | end | ||
360 | </pre> | ||
361 | </table> | ||
362 | |||
363 | |||
364 | <!-- cancelling +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
365 | <hr/> | ||
366 | <h2 id="cancelling">Cancelling</h2> | ||
367 | |||
368 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
369 | <code>bool= lane_h:cancel( [timeout_secs=0.0,] [force_kill_bool=false] )</code> | ||
370 | </table> | ||
371 | |||
372 | <p>Sends a cancellation request to the lane. If <tt>timeout_secs</tt> is non-zero, waits | ||
373 | for the request to be processed, or a timeout to occur. | ||
374 | Returns <tt>true</tt> if the lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status) | ||
375 | or if the cancellation was fruitful within timeout period. | ||
376 | </p><p> | ||
377 | If the lane is still running and <tt>force_kill</tt> is <tt>true</tt>, the | ||
378 | OS thread running the lane is forcefully killed. This means no GC, and should | ||
379 | generally be the last resort. | ||
380 | </p> | ||
381 | <p>Cancellation is tested before going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls | ||
382 | and after executing <tt>cancelstep</tt> Lua statements. A currently pending <tt>receive</tt> | ||
383 | or <tt>send</tt> call is currently not awakened, and may be a reason for a non-detected cancel. | ||
384 | </p> | ||
385 | |||
386 | |||
387 | <!-- finalizers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
388 | <hr/> | ||
389 | <h2 id="finalizers">Finalizers</h2> | ||
390 | |||
391 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
392 | <code>set_finalizer( finalizer_func )</code> | ||
393 | <br/><br/> | ||
394 | <code>void= finalizer_func( [error] )</code> | ||
395 | </table> | ||
396 | |||
397 | <p>The <tt>error</tt> call is used for throwing exceptions in Lua. What Lua | ||
398 | does not offer, however, is scoped <a href="http://en.wikipedia.org/wiki/Finalizer">finalizers</a> | ||
399 | that would get called when a certain block of instructions gets exited, whether | ||
400 | through peaceful return or abrupt <tt>error</tt>. | ||
401 | </p> | ||
402 | <p>Since 2.0.3, Lanes prepares a function <tt>set_finalizer</tt> for doing this. | ||
403 | Any functions given to it will be called in the lane Lua state, just prior to | ||
404 | closing it. They are not called in any particular order. | ||
405 | </p> | ||
406 | <p>An error in a finalizer itself overrides the state of the regular chunk | ||
407 | (in practise, it would be highly preferable <i>not</i> to have errors in finalizers). | ||
408 | If one finalizer errors, the others may not get called. | ||
409 | </p> | ||
410 | |||
411 | |||
412 | <!-- lindas +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
413 | <hr/> | ||
414 | <h2 id="lindas">Lindas</h2> | ||
415 | |||
416 | <p>Communications between lanes is completely detached from the lane handles | ||
417 | themselves. By itself, a lane can only provide return values once it's finished, | ||
418 | or throw an error. Needs to communicate during runtime are handled by <A HREF="http://en.wikipedia.org/wiki/Linda_%28coordination_language%29" TARGET="_blank">Linda objects</A>, which are | ||
419 | <A HREF="#deep_userdata">deep userdata</A> instances. They can be provided to a lane | ||
420 | as startup parameters, upvalues or in some other Linda's message. | ||
421 | </p><p> | ||
422 | Access to a Linda object means a lane can read or write to any of its data | ||
423 | slots. Multiple lanes can be accessing the same Linda in parallel. No application | ||
424 | level locking is required; each Linda operation is atomic. | ||
425 | </p><p> | ||
426 | |||
427 | <table border=1 bgcolor="#FFFFE0" width=500><tr><td> | ||
428 | <pre> | ||
429 | require "lanes" | ||
430 | |||
431 | local linda= lanes.linda() | ||
432 | |||
433 | local function loop( max ) | ||
434 | for i=1,max do | ||
435 | print( "sending: "..i ) | ||
436 | linda:send( "x", i ) -- linda as upvalue | ||
437 | end | ||
438 | end | ||
439 | |||
440 | a= lanes.gen("",loop)( 10000 ) | ||
441 | |||
442 | while true do | ||
443 | local val= linda:receive( 3.0, "x" ) -- timeout in seconds | ||
444 | if val==nil then | ||
445 | print( "timed out" ) | ||
446 | break | ||
447 | end | ||
448 | print( "received: "..val ) | ||
449 | end | ||
450 | </pre> | ||
451 | </table> | ||
452 | |||
453 | </p> | ||
454 | <p>Characteristics of the Lanes implementation of Lindas are: | ||
455 | |||
456 | <ul> | ||
457 | <li>keys can be of number, string or boolean type | ||
458 | </li> | ||
459 | <li>values can be any type supported by inter-state copying (same limits | ||
460 | as for function parameters and upvalues) | ||
461 | </li> | ||
462 | <li>consuming method is <tt>:receive</tt> (not in) | ||
463 | </li> | ||
464 | <li>non-consuming method is <tt>:get</tt> (not rd) | ||
465 | </li> | ||
466 | <li>two producer-side methods: <tt>:send</tt> and <tt>:set</tt> (not out) | ||
467 | </li> | ||
468 | <li><tt>send</tt> allows for sending multiple values -atomically- to a | ||
469 | given key | ||
470 | </li> | ||
471 | <li><tt>receive</tt> can wait for multiple keys at once | ||
472 | </li> | ||
473 | <li>individual keys' queue length can be limited, balancing speed differences | ||
474 | in a producer/consumer scenario (making <tt>:send</tt> wait) | ||
475 | </li> | ||
476 | </ul> | ||
477 | </p> | ||
478 | |||
479 | <p> | ||
480 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
481 | <code>h= lanes.linda()</code> | ||
482 | <br/><br/> | ||
483 | <code>bool= h:send( [timeout_secs,] key, ... )</code> | ||
484 | <br/> | ||
485 | <code>[val, key]= h:receive( [timeout_secs,] key [, ...] )</code> | ||
486 | <br/><br/> | ||
487 | <code>= h:limit( key, n_uint )</code> | ||
488 | </table> | ||
489 | |||
490 | <p>The <tt>send</tt> and <tt>receive</tt> methods use Linda keys as FIFO stacks | ||
491 | (first in, first out). Timeouts are given in seconds (millisecond accuracy). | ||
492 | If using numbers as the first Linda key, one must explicitly give <tt>nil</tt> | ||
493 | as the timeout parameter to avoid ambiguities. | ||
494 | </p><p> | ||
495 | By default, stack sizes are unlimited but limits can be | ||
496 | enforced using the <tt>limit</tt> method. This can be useful to balance execution | ||
497 | speeds in a producer/consumer scenario. | ||
498 | </p><p> | ||
499 | Note that any number of lanes can be reading or writing a Linda. There can be | ||
500 | many producers, and many consumers. It's up to you. | ||
501 | </p> | ||
502 | <p><tt>send</tt> returns <tt>true</tt> if the sending succeeded, and <tt>false</tt> | ||
503 | if the queue limit was met, and the queue did not empty enough during the given | ||
504 | timeout. | ||
505 | </p><p> | ||
506 | Equally, <tt>receive</tt> returns a value and the key that provided the value, | ||
507 | or nothing for timeout. Note that <tt>nil</tt>s can be sent and received; | ||
508 | the <tt>key</tt> value will tell it apart from a timeout. | ||
509 | </p><p> | ||
510 | Multiple values can be sent to a given key at once, atomically (the send will | ||
511 | fail unless all the values fit within the queue limit). This can be useful for | ||
512 | multiple producer scenarios, if the protocols used are giving data in streams | ||
513 | of multiple units. Atomicity avoids the producers from garbling each others | ||
514 | messages, which could happen if the units were sent individually. | ||
515 | </p><p> | ||
516 | |||
517 | When receiving from multiple slots, the keys are checked in order, which can | ||
518 | be used for making priority queues. | ||
519 | </p><p> | ||
520 | |||
521 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
522 | <code>linda_h:set( key, [val] )</code> | ||
523 | <br/> | ||
524 | <code>[val]= linda_h:get( key )</code> | ||
525 | </table> | ||
526 | |||
527 | </p><p> | ||
528 | The table access methods are for accessing a slot without queuing or consuming. | ||
529 | They can be used for making shared tables of storage among the lanes. | ||
530 | </p><p> | ||
531 | Writing to a slot overwrites existing value, and clears any possible queued | ||
532 | entries. Table access and <tt>send</tt>/<tt>receive</tt> can be used together; | ||
533 | reading a slot essentially peeks the next outcoming value of a queue. | ||
534 | </p> | ||
535 | |||
536 | <!-- | ||
537 | <p> | ||
538 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
539 | <code>lightuserdata= linda_h:deep()</code> | ||
540 | </table> | ||
541 | |||
542 | <p>There is one more method that is not required in applications, but | ||
543 | discussing it is good for a preview of how deep userdata works. | ||
544 | </p><p> | ||
545 | Because proxy objects (<tt>linda_h</tt>) are just pointers to the real, deep | ||
546 | userdata, they cannot be used to identify a certain Linda from the others. | ||
547 | The internal timer system needs to do this, and the <tt>:deep()</tt> method | ||
548 | has been added for its use. It returns a light userdata pointing to the | ||
549 | <i>actual</i> deep object, and thus can be used for seeing, which proxies actually | ||
550 | mean the same underlying object. You might or might not need a similar system | ||
551 | with your own deep userdata. | ||
552 | </p> | ||
553 | --> | ||
554 | |||
555 | |||
556 | <h3>Granularity of using Lindas</h3> | ||
557 | |||
558 | <p>A single Linda object provides an infinite number of slots, so why would | ||
559 | you want to use several? | ||
560 | </p><p>There are some important reasons: | ||
561 | |||
562 | <ul> | ||
563 | <li>Access control. If you don't trust certain code completely, or just | ||
564 | to modularize your design, use one Linda for one usage and another one | ||
565 | for the other. This keeps your code clear and readable. You can pass | ||
566 | multiple Linda handles to a lane with practically no added cost. | ||
567 | </li> | ||
568 | |||
569 | <li>Namespace control. Linda keys have a "flat" namespace, so collisions | ||
570 | are possible if you try to use the same Linda for too many separate uses. | ||
571 | </li> | ||
572 | |||
573 | <li>Performance. Changing any slot in a Linda causes all pending threads | ||
574 | for that Linda to be momentarily awakened (at least in the C level). | ||
575 | This can degrade performance due to unnecessary OS level context switches. | ||
576 | </li> | ||
577 | </ul> | ||
578 | |||
579 | On the other side, you need to use a common Linda for waiting for multiple | ||
580 | keys. You cannot wait for keys from two separate Linda objects at the same | ||
581 | time. | ||
582 | </p><p> | ||
583 | <font size="-1">Actually, you can. Make separate lanes to wait each, and then multiplex those | ||
584 | events to a common Linda, but... :).</font> | ||
585 | </p> | ||
586 | |||
587 | |||
588 | <!-- timers +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
589 | <hr/> | ||
590 | <h2 id="timers">Timers</h2> | ||
591 | |||
592 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td> | ||
593 | <code>= lanes.timer( linda_h, key, date_tbl|first_secs [,period_secs] )</code> | ||
594 | </table> | ||
595 | |||
596 | <p> | ||
597 | Timers can be run once, or in a reoccurring fashion (<tt>period_secs > 0</tt>). | ||
598 | The first occurrence can be given either as a date or as a relative delay in seconds. | ||
599 | The <tt>date</tt> table is like what <tt>os.date("*t")</tt> returns, in the | ||
600 | local time zone. | ||
601 | </p><p> | ||
602 | Once a timer expires, the <tt>key</tt> is set with the current time | ||
603 | (in seconds, same offset as <tt>os.time()</tt> but with millisecond accuracy). | ||
604 | The key can be waited upon using the regular Linda <tt>:receive()</tt> | ||
605 | method. | ||
606 | </p><p> | ||
607 | A timer can be stopped simply by <tt>first_secs=0</tt> and no period. | ||
608 | </p><p> | ||
609 | |||
610 | <table border=1 bgcolor="#FFFFE0" width=500><tr><td> | ||
611 | <pre> | ||
612 | require "lanes" | ||
613 | |||
614 | local linda= lanes.linda() | ||
615 | |||
616 | -- First timer once a second, not synchronized to wall clock | ||
617 | -- | ||
618 | lanes.timer( linda, "sec", 1, 1 ) | ||
619 | |||
620 | -- Timer to a future event (next even minute); wall clock synchronized | ||
621 | -- | ||
622 | local t= os.date( "*t", os.time()+60 ) -- now + 1min | ||
623 | t.sec= 0 | ||
624 | |||
625 | lanes.timer( linda, "min", t, 60 ) -- reoccur every minute (sharp) | ||
626 | |||
627 | while true do | ||
628 | local v,key= linda:receive( "sec", "min" ) | ||
629 | print( "Timer "..key..": "..v ) | ||
630 | end | ||
631 | </pre> | ||
632 | </table> | ||
633 | |||
634 | </p><p> | ||
635 | NOTE: Timer keys are set, not queued, so missing a beat is possible especially | ||
636 | if the timer cycle is extremely small. The key value can be used to know the | ||
637 | actual time passed. | ||
638 | </p><p> | ||
639 | <table> | ||
640 | <tr><td valign=top><nobr><i>Design note:</i></nobr> </td> | ||
641 | <td> | ||
642 | <font size="-1"> | ||
643 | Having the API as <tt>lanes.timer()</tt> is intentional. Another | ||
644 | alternative would be <tt>linda_h:timer()</tt> but timers are not traditionally | ||
645 | seen to be part of Lindas. Also, it would mean any lane getting a Linda handle | ||
646 | would be able to modify timers on it. A third choice could | ||
647 | be abstracting the timers out of Linda realm altogether (<tt>timer_h= lanes.timer( date|first_secs, period_secs )</tt>) | ||
648 | but that would mean separate waiting functions for timers, and lindas. Even if | ||
649 | a linda object and key was returned, that key couldn't be waited upon simultaneously | ||
650 | with one's general linda events. | ||
651 | The current system gives maximum capabilities with minimum API, and any smoothenings | ||
652 | can easily be crafted in Lua at the application level. | ||
653 | </font> | ||
654 | </td> | ||
655 | </tr> | ||
656 | </table> | ||
657 | </p> | ||
658 | |||
659 | |||
660 | <!-- locks +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
661 | <hr/> | ||
662 | <h2 id="locks">Locks etc.</h2> | ||
663 | |||
664 | <p> | ||
665 | Lanes does not generally require locks or critical sections to be used, at all. | ||
666 | If necessary, a limited queue can be used to emulate them. <tt>lanes.lua</tt> | ||
667 | offers some sugar to make it easy: | ||
668 | </p><p> | ||
669 | |||
670 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td><pre> | ||
671 | lock_func= lanes.genlock( linda_h, key [,N_uint=1] ) | ||
672 | |||
673 | lock_func( M_uint ) -- acquire | ||
674 | .. | ||
675 | lock_func( -M_uint ) -- release | ||
676 | </table> | ||
677 | </p><p> | ||
678 | |||
679 | The generated function acquires M entries from the N available, or releases | ||
680 | them if the value is negative. The acquiring call will suspend the lane, if necessary. | ||
681 | Use <tt>M=N=1</tt> for a critical section lock (only one lane allowed to enter). | ||
682 | </p><p> | ||
683 | |||
684 | Note: The locks generated are <u>not recursive</u>. That would need another | ||
685 | kind of generator, which is currently not implemented. | ||
686 | </p><p> | ||
687 | |||
688 | Similar sugar exists for atomic counters: | ||
689 | </p><p> | ||
690 | |||
691 | <table border=1 bgcolor="#E0E0FF" cellpadding=10><tr><td><pre> | ||
692 | atomic_func= lanes.genatomic( linda_h, key [,initial_num=0.0] ) | ||
693 | |||
694 | new_num= atomic_func( [diff_num=+1.0] ) | ||
695 | </table> | ||
696 | </p><p> | ||
697 | |||
698 | Each time called, the generated function will change <tt>linda[key]</tt> | ||
699 | atomically, without other lanes being able to interfere. The new value is | ||
700 | returned. You can use either <tt>diff 0.0</tt> or <tt>get</tt> to just read the current | ||
701 | value. | ||
702 | </p><p> | ||
703 | |||
704 | Note that the generated functions can be passed on to other lanes. | ||
705 | </p> | ||
706 | |||
707 | |||
708 | <!-- others +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
709 | <hr/> | ||
710 | <h2 id="other">Other issues</h2> | ||
711 | |||
712 | <h3>Limitations on data passing</h3> | ||
713 | |||
714 | <p>Data passed between lanes (either as starting parameters, return values, upvalues or via Lindas) must conform to the following: | ||
715 | </p> | ||
716 | <p><ul> | ||
717 | <li>Booleans, numbers, strings, light userdata, Lua functions and tables of such can always be passed. | ||
718 | </li> | ||
719 | <li>Cyclic tables and/or duplicate references are allowed and reproduced appropriately, | ||
720 | but only <u>within the same transmission</u>. | ||
721 | <ul> | ||
722 | <li>using the same source table in multiple Linda messages keeps no ties between the tables | ||
723 | </li> | ||
724 | </ul> | ||
725 | </li> | ||
726 | <li>Objects (tables with a metatable) are copyable between lanes. | ||
727 | <ul> | ||
728 | <li>metatables are assumed to be immutable; they are internally indexed and only copied once | ||
729 | per each type of objects per lane | ||
730 | </li> | ||
731 | </ul> | ||
732 | </li> | ||
733 | <li>C functions (<tt>lua_CFunction</tt>) referring to <tt>LUA_ENVIRONINDEX</tt> or <tt>LUA_REGISTRYINDEX</tt> might not | ||
734 | work right in the target | ||
735 | <ul> | ||
736 | <li>rather completely re-initialize a module with <tt>require</tt> in the target lane | ||
737 | </li> | ||
738 | </ul> | ||
739 | </li> | ||
740 | <li>Full userdata can be passed only if it's prepared using the <A HREF="#deep_userdata">deep userdata</A> | ||
741 | system, which handles its lifespan management | ||
742 | <ul> | ||
743 | <li>in particular, lane handles cannot be passed between lanes | ||
744 | </li> | ||
745 | </ul> | ||
746 | </li> | ||
747 | <li>coroutines cannot be passed | ||
748 | </li> | ||
749 | </ul> | ||
750 | </p> | ||
751 | |||
752 | |||
753 | <h3>Required of module makers</h3> | ||
754 | |||
755 | <p> | ||
756 | Most Lua extension modules should work unaltered with Lanes. | ||
757 | If the module simply ties C side features to Lua, everything is fine without | ||
758 | alterations. The <tt>luaopen_...()</tt> entry point will be called separately for each | ||
759 | lane, where the module is <tt>require</tt>'d from. | ||
760 | </p><p> | ||
761 | If it, however, also does one-time C side initializations, these | ||
762 | should be covered into a one-time-only construct such as below. | ||
763 | </p><p> | ||
764 | |||
765 | <table><tr><td width=40> | ||
766 | <td bgcolor="#ffffe0"> | ||
767 | <pre> | ||
768 | int luaopen_module( lua_State *L ) | ||
769 | { | ||
770 | static char been_here; /* 0 by ANSI C */ | ||
771 | |||
772 | /* Calls to 'require' serialized by Lanes; this is safe. | ||
773 | */ | ||
774 | if (!been_here) { | ||
775 | been_here= 1; | ||
776 | ... one time initializations ... | ||
777 | } | ||
778 | |||
779 | ... binding to Lua ... | ||
780 | } | ||
781 | </pre> | ||
782 | </td></tr></table> | ||
783 | </p> | ||
784 | |||
785 | |||
786 | <h3 id="shared_userdata">Deep userdata in your own apps</h3> | ||
787 | |||
788 | <p> | ||
789 | The mechanism Lanes uses for sharing Linda handles between separate Lua states | ||
790 | can be used for custom userdata as well. Here's what to do. | ||
791 | </p> | ||
792 | <ol> | ||
793 | <li>Provide an <i>identity function</i> for your userdata, in C. This function is | ||
794 | used for creation and deletion of your deep userdata (the shared resource), | ||
795 | and for making metatables for the state-specific proxies for accessing it. | ||
796 | Take a look at <tt>linda_id</tt> in <tt>lanes.c</tt>. | ||
797 | </li> | ||
798 | <li>Create your userdata using <tt>luaG_deep_userdata()</tt>, which is | ||
799 | a Lua-callable function. Given an <tt>idfunc</tt>, it sets up the support | ||
800 | structures and returns a state-specific proxy userdata for accessing your | ||
801 | data. This proxy can also be copied over to other lanes. | ||
802 | </li> | ||
803 | <li>Accessing the deep userdata from your C code, use <tt>luaG_todeep()</tt> | ||
804 | instead of the regular <tt>lua_touserdata()</tt>. | ||
805 | </li> | ||
806 | </ol> | ||
807 | |||
808 | <p>Deep userdata management will take care of tying to <tt>__gc</tt> methods, | ||
809 | and doing reference counting to see how many proxies are still there for | ||
810 | accessing the data. Once there are none, the data will be freed through a call | ||
811 | to the <tt>idfunc</tt> you provided. | ||
812 | </p> | ||
813 | <p><b>NOTE</b>: The lifespan of deep userdata may exceed that of the Lua state | ||
814 | that created it. The allocation of the data storage should not be tied to | ||
815 | the Lua state used. In other words, use <tt>malloc</tt>/<tt>free</tt> or | ||
816 | similar memory handling mechanism. | ||
817 | </p> | ||
818 | |||
819 | |||
820 | <h3>Lane handles don't travel</h3> | ||
821 | |||
822 | <p> | ||
823 | Lane handles are not implemented as deep userdata, and cannot thus be | ||
824 | copied across lanes. This is intentional; problems would occur at least when | ||
825 | multiple lanes were to wait upon one to get ready. Also, it is a matter of | ||
826 | design simplicity. | ||
827 | </p><p> | ||
828 | The same benefits can be achieved by having a single worker lane spawn all | ||
829 | the sublanes, and keep track of them. Communications to and from this lane | ||
830 | can be handled via a Linda. | ||
831 | </p> | ||
832 | |||
833 | |||
834 | <h3>Beware with print and file output</h3> | ||
835 | |||
836 | <p> | ||
837 | In multithreaded scenarios, giving multiple parameters to <tt>print()</tt> | ||
838 | or <tt>file:write()</tt> may cause them to be overlapped in the output, | ||
839 | something like this: | ||
840 | |||
841 | <pre> | ||
842 | A: print( 1, 2, 3, 4 ) | ||
843 | B: print( 'a', 'b', 'c', 'd' ) | ||
844 | |||
845 | 1 a b 2 3 c d 4 | ||
846 | </pre> | ||
847 | |||
848 | Lanes does not protect you from this behaviour. The thing to do is either to | ||
849 | concentrate your output to a certain lane per stream, or to concatenate output | ||
850 | into a single string before you call the output function. | ||
851 | </p> | ||
852 | |||
853 | |||
854 | <h3 id="performance">Performance considerations</h3> | ||
855 | |||
856 | <p> | ||
857 | Lanes is about making multithreading easy, and natural in the Lua state of mind. | ||
858 | Expect performance not to be an issue, if your program is logically built. | ||
859 | Here are some things one should consider, if best performance is vital: | ||
860 | </p><p> | ||
861 | <ul> | ||
862 | <li>Data passing (parameters, upvalues, Linda messages) is generally fast, | ||
863 | doing two binary state-to-state copies (from source state to hidden state, | ||
864 | hidden state to target state). Remember that not only the function you | ||
865 | specify but also its upvalues, their upvalues, etc. etc. will get copied. | ||
866 | </li> | ||
867 | <li>Lane startup is fast (1000's of lanes a second), depending on the | ||
868 | number of standard libraries initialized. Initializing all standard libraries | ||
869 | is about 3-4 times slower than having no standard libraries at all. If you | ||
870 | throw in a lot of lanes per second, make sure you give them minimal necessary | ||
871 | set of libraries. | ||
872 | </li> | ||
873 | <li>Waiting Lindas are woken up (and execute some hidden Lua code) each | ||
874 | time <u>any</u> key in the Lindas they are waiting for are changed. This | ||
875 | may give essential slow-down (not measured, just a gut feeling) if a lot | ||
876 | of Linda keys are used. Using separate Linda objects for logically separate | ||
877 | issues will help (which is good practise anyhow). | ||
878 | </li> | ||
879 | <li>Linda objects are light. The memory footprint is two OS-level signalling | ||
880 | objects (<tt>HANDLE</tt> or <tt>pthread_cond_t</tt>) for each, plus one | ||
881 | C pointer for the proxies per each Lua state using the Linda. Barely nothing. | ||
882 | </li> | ||
883 | <li>Timers are light. You can probably expect timers up to 0.01 second | ||
884 | resolution to be useful, but that is very system specific. All timers are | ||
885 | merged into one main timer state (see <tt>timer.lua</tt>); no OS side | ||
886 | timers are utilized. | ||
887 | </li> | ||
888 | <li>Lindas are hashed to a fixed number of "keeper states", which are a locking entity. | ||
889 | If you are using a lot of Linda objects, | ||
890 | it may be useful to try having more of these keeper states. By default, | ||
891 | only one is used (see <tt>KEEPER_STATES_N</tt>), but this is an implementation detail. | ||
892 | </li> | ||
893 | </ul> | ||
894 | </p> | ||
895 | |||
896 | |||
897 | <h3 id="cancelling_cancel">Cancelling cancel</h3> | ||
898 | |||
899 | <p> | ||
900 | Cancellation of lanes uses the Lua error mechanism with a special lightuserdata | ||
901 | error sentinel. | ||
902 | If you use <tt>pcall</tt> in code that needs to be cancellable | ||
903 | from the outside, the special error might not get through to Lanes, thus | ||
904 | preventing the Lane from being cleanly cancelled. You should throw any | ||
905 | lightuserdata error further. | ||
906 | </p><p> | ||
907 | This system can actually be used by application to detect cancel, do your own | ||
908 | cancellation duties, and pass on the error so Lanes will get it. If it does | ||
909 | not get a clean cancellation from a lane in due time, | ||
910 | it may forcefully kill the lane. | ||
911 | </p><p> | ||
912 | The sentinel is exposed as <tt>lanes.cancel_error</tt>, if you wish to use | ||
913 | its actual value. | ||
914 | </p> | ||
915 | |||
916 | |||
917 | |||
918 | <!-- change log +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
919 | <hr/> | ||
920 | <h2 id="changes">Change log</h2> | ||
921 | |||
922 | <p> | ||
923 | Jan-2009 (2.0.3): | ||
924 | <ul> | ||
925 | <li>Added 'finalizer' to lane options. (TBD: not implemented yet!) | ||
926 | </li> | ||
927 | <li>Added call stack to errors coming from a lane. | ||
928 | </li> | ||
929 | </ul> | ||
930 | |||
931 | Jul-2008 (2.0): | ||
932 | <ul> | ||
933 | <li>Too many changes to list (you'll need to re-read this manual) | ||
934 | </li> | ||
935 | </ul> | ||
936 | </p> | ||
937 | |||
938 | <!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | ||
939 | <hr/> | ||
940 | |||
941 | <p>For feedback, questions and suggestions: | ||
942 | <UL> | ||
943 | <li><A HREF="http://luaforge.net/projects/lanes">Lanes @ LuaForge</A></li> | ||
944 | <li><A HREF="mailto:akauppi@gmail.com">the author</A></li> | ||
945 | </UL> | ||
946 | </p> | ||
947 | |||
948 | <p><br/></p> | ||
949 | |||
950 | </body> | ||
951 | </html> | ||
diff --git a/docs/multi.png b/docs/multi.png new file mode 100644 index 0000000..f527aff --- /dev/null +++ b/docs/multi.png | |||
Binary files differ | |||
diff --git a/docs/performance.ods b/docs/performance.ods new file mode 100644 index 0000000..541cc8e --- /dev/null +++ b/docs/performance.ods | |||
Binary files differ | |||