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 | |||
