diff options
author | nicholas-leonard <nick@nikopia.org> | 2015-01-09 19:43:12 +0300 |
---|---|---|
committer | nicholas-leonard <nick@nikopia.org> | 2015-01-09 21:06:48 +0300 |
commit | 86b4ae0cee9654d2f48ffdc000e87fa31d958fde (patch) | |
tree | 66f75a565db57ba0f498f1dc33555ca585bb4bc2 /README.md | |
parent | a3c358105350ace8bcc61e94c4bc028f3aaa3e02 (diff) |
Example lua code + library documentation
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 144 |
1 files changed, 107 insertions, 37 deletions
@@ -21,8 +21,9 @@ The magic of the *threads* package lies in the seven following points: # Installation # -At this time *threads* relies on two other packages: *torch* (for -serialization) and *SDL2* for threads. +At this time *threads* relies on two other packages: + * [Torch7](torch.ch) (for serialization) ; and + * [SDL2](https://github.com/torch/sdl2-ffi/blob/master/README.md) for threads. One could certainly port easily this package to other threading API (pthreads, Windows threads...), but as SDL2 is really easy to install, and @@ -30,8 +31,8 @@ very portable, I believe this dependency should not be a problem. If there are enough requests, I might propose alternatives to SDL2 threads. Torch is used for full serialization. One could easily get inspired from -Torch serialization system to adapt the package to its own needs. Soon -(with torch9), Torch should be straighforward to install, so this +Torch serialization system to adapt the package to its own needs. +Torch should be straighforward to install, so this dependency should be minor too. At this time, if you have torch7 installed: @@ -40,9 +41,9 @@ luarocks install https://raw.github.com/torch/sdl2-ffi/master/rocks/sdl2-scm-1.r luarocks install https://raw.github.com/torch/threads-ffi/master/rocks/threads-scm-1.rockspec ``` -# Example Usage # +# Examples # -An example is better than convoluted explanations. +A [simple example](example/simple.md) is better than convoluted explanations: ```lua local Threads = require 'threads' @@ -61,41 +62,44 @@ sdl.init(0) -- the function takes several callbacks as input, which will be executed -- sequentially on each newly created lua state local threads = Threads(nthread, - -- typically the first callback requires modules - -- necessary to serialize other callbacks - function() - gsdl = require 'sdl2' - end, - - -- other callbacks (one is enough in general!) prepare stuff - -- you need to run your program - function(idx) - print('starting a new thread/state number:', idx) - gmsg = msg -- we copy here an upvalue of the main thread - end) + -- typically the first callback requires modules + -- necessary to serialize other callbacks + function() + gsdl = require 'sdl2' + end, + + -- other callbacks (one is enough in general!) prepare stuff + -- you need to run your program + function(idx) + print('starting a new thread/state number:', idx) + gmsg = msg -- we copy here an upvalue of the main thread + end +) -- now add jobs local jobdone = 0 for i=1,njob do threads:addjob( - -- the job callback - function() - local id = tonumber(gsdl.threadID()) - print(string.format('%s -- thread ID is %x', gmsg, id)) - - -- return a value to the end callback - return id - end, - - -- the end callback - -- ran in the main thread - function(id) - print(string.format("task %d finished (ran on thread ID %x)", i, id)) - - -- note that we can manipulate upvalues of the main thread - -- as this callback is ran in the main thread! - jobdone = jobdone + 1 - end) + -- the job callback + function() + local id = tonumber(gsdl.threadID()) + -- note that gmsg was intialized in last worker callback + print(string.format('%s -- thread ID is %x', gmsg, id)) + + -- return a value to the end callback + return id + end, + + -- the end callback runs in the main thread. + -- takes output of the previous function as argument + function(id) + print(string.format("task %d finished (ran on thread ID %x)", i, id)) + + -- note that we can manipulate upvalues of the main thread + -- as this callback is ran in the main thread! + jobdone = jobdone + 1 + end + ) end -- wait for all jobs to finish @@ -139,7 +143,73 @@ task 10 finished (ran on thread ID cec8000) 10 jobs done ``` -# Advanced Example # +## Advanced Example ## See a neural network [threaded training example](benchmark/README.md) for a more advanced usage of `threads`. + +# Library # + +## Threads ## +This class is used to manage a set of worker threads. The class is +returned upon requiring the package: + +```lua +Threads = require 'threads' +``` + +### Threads(N,[f1,f2,...]) ### +Argument `N` of this constructor specifies the number of worker threads +that will be spawned. The optional arguments `f1,f2,...` can be a list +of functions to execute in each worker thread. To be clear, all of +these functions will be executed in each thread. However, each optional +function `f` takes an argument `threadIdx` which is a number between +`1` and `N` identifying each thread. This could be used to make each +thread have different behaviour. + +Example: +```lua +Threads(4, + function(threadIdx) + print("Initializing thread " .. threadIdx) + end +) +``` + +### Threads:addjob(callback, [endcallback, ...]) ### +This method is used to queue the execution of jobs in the worker threads. +The `callback` is function that will be executed in each worker thread. +It arguments are the optional `...`. +The `endcallback` is a function that will be executed in the main thread +(the one calling this method). + +Before being executed in the worker thread, the `callback` is serialized +by the main thread and unserialized by the worker. The main thread can +thus transfer data to the worker by using upvalues: +```lua +local upvalue = 10 +threads:addjob( + function() + workervalue = upvalue + return 1 + end, + function(inc) + upvalue = upvalue + inc + end +) +``` +In the above example, each worker will have a global variable `workervalue` +which will contain a copy of the main thread's `upvalue`. Note that +if the main thread's upvalue were global, as opposed to `local` +it would not be an upvalue, and therefore would not be serialized along +with the `callback`. In which case, `workervalue` would be `nil`. + +In the same example, the worker also communicates a value to the main thread. +This is accomplished by having the `callback` return one ore many values which +will be serialized and unserialized as arguments to the `endcallback` function. +In this case a value of `1` is received by the main thread as argument `inc` to the +`endcallback` function, which then uses it to increment `upvalue`. This +demonstrates how communication between threads is easily achieved using +the `addjob` method. + +### Threads:dojob( |