I’m playing around with .Net MXS Multi Threading and search a solution for: How to execute a function (multi threaded) with a parameter. Google didn’t help me so far.
Here’s the code which has two problems:
[ol]
[li]The code drops an error after executing the multi thread function (this can be prevented by try/catch)[/li][li]3Ds Max stalls, during execution! This is then of course useless since this shall not happen with multi threading[/li][/ol]
fn doSomeStuff myText =
(
for i = 1 to 1000000 do pi * pi * pi
print myText
print "thread done ..."
)
myThread = dotNetObject "system.componentModel.backgroundWorker"
dotnet.addEventHandler myThread "DoWork" (doSomeStuff "test")
myThread.runWorkerAsync()
– Runtime error: dotNet event handler must be a functions, got: “test”
If you delete the function parameter and the parenthesis, the code works perfectly - no 3Ds Max stalling and no error. But i need to hand over a function parameter! Is this just not possible?
This is black magic! But it works, thank you! But i got problems with the variables scope and since i don’t want to use global variables, i looked for another solution and found one. You can hand over an argument when starting the thread with “RunWorkersAsync” and here’s a great example how to use this with arrays:
--------------------------------------------------MULTITHREADING DEFINITION--------------------------------------------------
global prog_rol, --#(progressform, #(progressbars))
tasks = #(), --array of tasks, every task'll be executed in separate thread
finished = 0, --finished tasks count
senders = #() --task senders
fn progcreate state =
(
hForm = dotNetObject "System.Windows.Forms.Form"
hForm.clientsize = dotNetObject "System.Drawing.Size" 500 (20*tasks.count)
hForm.FormBorderStyle = hForm.FormBorderStyle.FixedToolWindow
hForm.StartPosition = hForm.StartPosition.CenterScreen
hForm.TopMost = true
hform.text = state
bars = #()
for i = 1 to tasks.count do
(
prog = dotNetObject "System.windows.forms.ProgressBar"
prog.size = dotNetObject "System.Drawing.Size" 500 20
prog.location = dotNetObject "System.Drawing.Point" 0 (20*(i - 1))
prog.value = 0
hForm.controls.add prog
append bars prog
)
hForm.show()
progressStart state
prog_rol = #(hForm,bars)
)
fn progupdate sender task =
(
try --to avoid error if progressform's closed
(
overall = 0
for bid = 1 to prog_rol[2].count do
(
bar = prog_rol[2][bid]
if bid == task.userstate then
bar.value = task.progresspercentage
overall += bar.value
)
progressupdate (overall*100/(tasks.count*100)) --refresh global progress
) catch()
)
fn checkresult =
(
if finished == (tasks.count - 1) then
(
free tasks
free senders
prog_rol[1].close()
progressend()
messagebox "All tasks're finished!"
)
else
finished += 1
)
fn dowork processname =
(
senders = #()
if tasks.count > 0 then
(
progcreate processname
finished = 0
bwthreads = #()
for task in tasks do
(
thread = (dotnetobject "System.ComponentModel.BackGroundWorker")
thread.WorkerReportsProgress = true
dotNet.addEventHandler thread "DoWork" task[3]
dotNet.addEventHandler thread "ProgressChanged" progupdate
dotNet.addEventHandler thread "RunWorkerCompleted" checkresult
append bwthreads thread
)
for tid = 1 to bwthreads.count do
bwthreads[tid].RunWorkerAsync tid --run thread with thread ID as parameter
free bwthreads
)
)
--------------------------------------------------USER FUNCTIONS--------------------------------------------------
fn testfn1 endval taskid =
(
sender = senders[taskid]
for i = 1 to endval do
(
--some work
sender.ReportProgress ((i as float)/endval*100) taskid
sleep 0.05
)
)
fn testfn1_prototype sender thread =
(
try
(
task = tasks[thread.argument]
senders[thread.argument] = sender
task[1] task[2][1] thread.argument --execute target function with 1 paramater and task ID
)
catch
sender.ReportProgress 100 thread.argument --finish task on error
)
fn testfn2 endval freezetime taskid =
(
sender = senders[taskid]
for i = 1 to endval do
(
--some work
sender.ReportProgress ((i as float)/endval*100) taskid
sleep freezetime
)
)
fn testfn2_prototype sender thread =
(
try
(
task = tasks[thread.argument]
senders[thread.argument] = sender
task[1] task[2][1] task[2][2] thread.argument --execute target function with 2 paramaters and task ID
)
catch
sender.ReportProgress 100 thread.argument --finish task on error
)
--------------------------------------------------FUNCTION CALLS--------------------------------------------------
task1 = #(testfn1,#(100),testfn1_prototype) --task syntax: #(<function name>, #(<function parameters>), <function prototype name>)
task2 = #(testfn2,#(50,0.2),testfn2_prototype)
tasks = #(task1,task2,task1,task2) --launch 4 threads(functions can repeat)
dowork "Multithreading test" --launch tasks