[Closed] superClassOf in multithreading
Have you ever tried to use the function superClassOf in multithreading?
Several days I was investigating how to make my scripter faster by using multithreading, but Max crashes everytime if I use 2 threads. I made completely different variables and functions for every thread, but still 3D max crashes. I tried step by step to find out what’s the reason, the reason was this line when using simultaniously
if superClassOf prop == Material then …
both functions and variables are completelly different.
Is there a way to replace the function superClassOf with anything else, I need to find out if prop is a material or not.
ClassOf does not fit.
the fanny thing is that I use
IsKindOf
in the same script a little bellow, It really doesn’t crash max as superClassOf, but another problem arose that kills max in multithreading. I came to the conclusion that the scanning of two different materials in different threads is impossible anyway
w1 = undefined
w2 = undefined
fn work1 = (
w1 = for i=1 to 24 collect superclassof meditmaterials[i]
)
fn work2 = (
w2 = for i=1 to 24 collect ( iskindof meditmaterials[i] material )
)
mythreads = #()
myThreads[1] = dotNetObject "CSharpUtilities.SynchronizingBackgroundWorker"
myThreads[2] = dotNetObject "CSharpUtilities.SynchronizingBackgroundWorker"
dotnet.addEventHandler myThreads[1] "DoWork" work1
dotnet.addEventHandler myThreads[2] "DoWork" work2
myThreads[1].runworkerasync()
myThreads[2].runworkerasync()
max2014x64 works fine
yes, this is very simple, but I wanted to use multithreading for a deep material scanning like this code:
(
struct matDef (mat, path)
local getSubmats, subMats = #()
fn capitalizeFirst str =
toUpper str[1] + subString str 2 -1
fn formatName mat index: =
if isKindOf mat TextureMap OR index == unsupplied then
capitalizeFirst ((classOf mat) as string) + "\\"
else (substituteString (getSubTexmapSlotName mat index) " map" "") + "\\"
fn getSubmatsRecurse mat matInst path:"" =
for propName in (getPropNames mat) do
(
local prop = getProperty mat propname
if superClassOf prop == Material then
getSubmats prop path:path \
format:(capitalizeFirst (propname as string) + "\\" + formatName prop)
else if classOf prop == ArrayParameter do
for sub = 1 to prop.count where superClassOf prop[sub] == Material do
getSubmats prop[sub] path:path \
format:("Map" + sub as string + "\\" + formatName prop[sub])
)
fn getSubmats mat path:"" format:"" =
(
local matInst = matDef mat:mat path:(path + format)
append subMats matInst
getSubmatsRecurse mat matInst path:(path + format)
subMats
)
fn recurseMat mat path:"" =
for i = 1 to (getNumSubTexmaps mat)
where (local map = getSubTexmap mat i) != undefined do
if getNumSubTexmaps map > 0 then
recurseMat map path:(path + formatName mat index:i)
else if isKindOf map BitmapTexture do
(
format "Texture: %
" map.filename
format (path + formatName mat index:i + "
")
)
local current_mtl = mEdit.getCurMtl()
local subMatInsts = getSubmats current_mtl
format "
Base material: %
" (classOf current_mtl)
for matInst in subMatInsts do
recurseMat matInst.mat path:("MAP TREE: " + matInst.path)
swordsplayer helped me one day with this code, and it’s working just fine for my needs, but in big scenes with many materials and textures it takes long to calculate. It gives me the map tree that is very important for me to be displayed.
i think the problem is the using of recursion in another than main thread…
probably you have to define all recursive functions inside a function which you call with a BackgroundWorker’s work
Denis, you’re right. After changing SuperClassOf with isKindOf, the next bottle neck was the recursion. But I think, what I need is impossible to do without recursion and as a result is impossible to do in multithreading.
Denis, I have just noticed what you said, to define all recursive functions inside a function. How could I read this and not notice ))
Please tell me, how to do that? Please…
you have to define recursive function inside “work” function:
ww = #(#(),#())
meditmaterials[1] = multimaterial numsubs:(random 60 100)
meditmaterials[2] = multimaterial numsubs:(random 60 100)
fn work1 s e =
(
fn collectMats mat mats:#() fun: =
(
if iskindof mat Material and (appendifunique mats mat) do for k=1 to getNumSubMtls mat where (m = getSubMtl mat k) != undefined do
(
if (appendifunique mats m) do fun mat mats:mats fun:fun
)
ok
)
collectmats meditmaterials[1] mats:ww[1] fun:collectmats
s.Dispose()
)
fn work2 s e =
(
fn collectMats mat mats:#() fun: =
(
if iskindof mat Material and (appendifunique mats mat) do for k=1 to getNumSubMtls mat where (m = getSubMtl mat k) != undefined do
(
if (appendifunique mats m) do fun mat mats:mats fun:fun
)
ok
)
collectmats meditmaterials[2] mats:ww[2] fun:collectmats
s.Dispose()
)
mythreads = #()
myThreads[1] = dotNetObject "CSharpUtilities.SynchronizingBackgroundWorker"
myThreads[2] = dotNetObject "CSharpUtilities.SynchronizingBackgroundWorker"
dotnet.addEventHandler myThreads[1] "DoWork" work1
dotnet.addEventHandler myThreads[2] "DoWork" work2
myThreads[1].runworkerasync()
myThreads[2].runworkerasync()
while (myThreads[1].IsBusy or myThreads[2].IsBusy) and (not keyboard.escPressed) do ()
format "1 done:(%) - %
" ww[1].count ww[1]
format "2 done:(%) - %
" ww[2].count ww[2]
both workers can use the same event function. in this case you have to pass specific settings (where or what to search for example) with a worker. i’ve showed how to extend BackgroundWorker with adding tag property for example.