The following example compiles and runs fine with nimrod 0.9.4:
import os, times, osproc, locks
const num_files = 8
type Param_in = tuple[src, dest: string]
var
threads: seq[TThread[void]]
global_pos = 0
success_conversions = 0
input_params: seq[Param_in]
L: TLock
L.initLock
proc render_input() {.thread.} =
while true:
L.acquire
if global_pos >= input_params.len:
L.release
return
var pos = global_pos
global_pos.inc
L.release
echo input_params[pos].src
echo input_params[pos].dest
success_conversions.atomicInc
proc thread_test() =
let cpus = countProcessors()
global_pos = 0
input_params = newSeq[Param_in](num_files)
for f in 0 .. <num_files:
input_params[f] = ("something.rst", "tmanual" & $f & ".html")
threads = newSeq[TThread[void]](cpus)
for f in 0 .. <cpus: createThread[void](threads[f], render_input)
threads.join_threads
proc test() =
let t1 = epoch_time()
thread_test()
let t2 = epoch_time()
echo "Spent ", $(t2 - t1)
when isMainModule:
test()
echo "Test finished successfully"
However the current devel branch compiler complaints with Error: 'process' is not GC-safe. Presumably global variables are the way to share memory among threads, so how am I meant to make it work now?
import threadpool
proc render_input(src, dest: string) {.thread.} =
echo src
echo dest
proc thread_test() =
when true:
# version 1: with 'parallel'
parallel:
for f in 0 .. <num_files:
spawn render_input("something.rst", "tmanual" & $f & ".html")
else:
# version 2: with 'spawn' and 'sync'
for f in 0 .. <num_files:
spawn render_input("something.rst", "tmanual" & $f & ".html")
sync()
proc test() =
let t1 = epoch_time()
thread_test()
let t2 = epoch_time()
echo "Spent ", $(t2 - t1)
when isMainModule:
test()
echo "Test finished successfully"
Warning: parallel and spawn have not extensively been tested yet.
Using Araq's example as reference, I added ThreadPool multi-threading to the RayTrace benchmark here. On my Phenom II X4 920 (4-core CPU) ray-tracing a 720p*8 image split into 8*8 tiles completes in ~5sec with parallel/spawn multi-threading compared to ~19.4sec rendering the entire image on a single thread. So looks like ThreadPool is working well and is very easy to use. Nice job.
ps. If you want to try it, compile with -d:bigImg and compare to -d:bigImgMT --threads:on. There's also -d:noSave if you don't want it saving a 10240x5760 raw image to your disk every time you run the test.
[EDIT] Araq, question about this... i'm casting a ref array (Pixmap) to a ptr array in order to make this work. Each job spawned only edits it's own portion of the array though. If i don't, the whole image is black (zero). Is casting safe for this scenerio (since no threads read/write the same memory)? Or is there a better way to avoid needing the cast? I see there is not documentation on ThreadPool yet.