HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Threads, Waits, & Code Variables

07-10-2005, 02:35 AM#1
Heptameron
I have several questions and clarifications I want to make. I could probably figure several of these out myself, but I just wanted to pick some brains first.

1. Threads are cooperative, right? I mean, a thread will just keep executing until it yields with a TriggerSleepAction() call, or it gets killed by dividing by zero or some such, or spawns a new thread, or ends. Basically, I just want to be sure that if I start a thread, it won't yield until I have a chance to read from a temporary global variable, or something. Is that a safe thing to do?

2. Along the same lines: what happens with ExecuteFunc() and triggers executing? Do they interrupt the current thread and spawn a new one, or do they wait until the current thread isn't executing and then start the new thread executing? I'm just wondering if it's always safe to do something like:
Code:
function CallThisFunction takes integer i returns nothing
    set udg_SomeIntegerVariable = i
    call ExecuteFunc("ChildFunction")
endfunction

function ChildFunction takes nothing returns nothing
    local integer i = udg_SomeIntegerVariable
    [i](do something with i)[/i]
endfunction
Is this ever going to get corrupted if there are multiple calls to CallThisFunction()? What if that used TriggerExecute()?

3. Can you compare code variables? Such as, say:
Code:
function CompareCode takes code aFunction returns boolean
    return ( aFunction == function SomeOtherFunction )
endfunction
Will that work?

4. Can you use the return bug with code variables? Does it work reliably?

5. What's a good way to test threads? I mean, to see if something runs in a new thread or in the same one, when it starts running, etc... is there a good way to yield to other threads without the forced quarter-second wait of TriggerSleepAction()?

6. Is there anything else I'd need to know to make a bullet-proof, thread-safe, not-slow-as-molasses system for executing arbitrary functions with parameters?

7. Misc. question... can you use a custom Blizzard.j or common.j in a map? I heard that they didn't load under some circumstances; what were those circumstances, and does anyone know if that's still the case?

8. Another misc. question... how fast is accessing a game cache compared to setting a global variable? Has it ever made a noticeable difference for you?

I probably have more questions, but that should do for now...
07-10-2005, 04:38 AM#2
SektorGaza
1,2. first of you execute a function differently by just calling it like call ChildFunction() and the chld function, since you call it from function callthisfunction has to be above. and no, i don't believe it will every mess up, it's sequential paradigm, everything is executed in order. as long as you don't call child function by itself from anywhere else, you should be fine. i think thats why there's trigger queue. events simulate interrupts, only these interrupts don't halt everything and execute right away, but wait their turn probably, that's the way I see it, otherwise there would be serious hell. But Trigger sleep function is whole different story, since you don't want to waste time waiting for wait function to finish, I think other fuctions/triggers are executed while wait takes place. and when trigger sleep is over, the function where this triggersleep took place is executed forward, maybe it even has highest priority on queue.

3. yes you can compare code by returning comparison like return a > b and it will return if its true or false. and hense you can say something like "return IntegerOne() > IntegerTwo() which will call these two function which return integer.

4. return bugs are reliable with anything

5. good way to test threads is to print messages on the screen which functions are executing (you have to identify these functions somehow and obviously know their order)

6. dunno

7. i think not, only add your own jass functions to custom script code field in front of all triggers.

8. well when storing something in cache you give it like 3 or 4 variables of different type, etc. so obviously it's slower than setting a single variable of for ex. integer. it's not noticible though as long as you don't have a loop function like even : every .1 seconds or something, then you are probably in trouble.


hope i helped, feel free to correct me anyone else
07-11-2005, 12:16 AM#3
Heptameron
Quote:
Originally Posted by SektorGaza
first of you execute a function differently by just calling it like call ChildFunction() and the chld function, since you call it from function callthisfunction has to be above.
Yeah, I know how that works, but that isn't dynamic at all, like ExecuteFunc() is. I know how it works normally; I have questions about this way.

Quote:
Originally Posted by SektorGaza
and no, i don't believe it will every mess up, it's sequential paradigm, everything is executed in order. as long as you don't call child function by itself from anywhere else, you should be fine. i think thats why there's trigger queue. events simulate interrupts, only these interrupts don't halt everything and execute right away, but wait their turn probably, that's the way I see it, otherwise there would be serious hell. But Trigger sleep function is whole different story, since you don't want to waste time waiting for wait function to finish, I think other fuctions/triggers are executed while wait takes place. and when trigger sleep is over, the function where this triggersleep took place is executed forward, maybe it even has highest priority on queue.
That's what I thought. I just need confirmation on the "wait your turn" bit.

Quote:
Originally Posted by SektorGaza
3. yes you can compare code by returning comparison like return a > b and it will return if its true or false. and hense you can say something like "return IntegerOne() > IntegerTwo() which will call these two function which return integer.
How the heck will one function be greater than or less than another? My question doesn't have anything to do with integers. I don't see any reason you couldn't do something like "function SomeFunction == function SomeFunction", but there aren't code arrays, so I thought they might be special somehow.

Quote:
Originally Posted by SektorGaza
4. return bugs are reliable with anything
That's good to hear, but it is a bug, and bugs aren't always consistent.

Quote:
Originally Posted by SektorGaza
5. good way to test threads is to print messages on the screen which functions are executing (you have to identify these functions somehow and obviously know their order)
But with threads, as far as I know, you can't always predict if they'll execute the same way all the times; so would you just have to do that over and over to see if they came out right every time?

Quote:
Originally Posted by SektorGaza
7. i think not, only add your own jass functions to custom script code field in front of all triggers.
That's not the answer to the question. I know how that works. I have good reasons for what I want to do...

Quote:
Originally Posted by SektorGaza
8. well when storing something in cache you give it like 3 or 4 variables of different type, etc. so obviously it's slower than setting a single variable of for ex. integer. it's not noticible though as long as you don't have a loop function like even : every .1 seconds or something, then you are probably in trouble.
I don't see how "every 0.10 seconds" would have a problem with game cache... unless the functions are so slow they take 0.1 seconds each... and I know they aren't that bad.
07-11-2005, 12:26 AM#4
Vexorian
The only type that doesn't work correctly with return bug is string, you should never use it with string, seriously, code, real ,boolean, and all the handle family work well.

The return bug It is not a bug actually, it is a Type cast method that is even used by blizzard.

I will tell you my explanation for threads:


Code:
 function funa takes nothing returns nothing
     call BJDebugMsg(I2S(globvar))
endfunction

function funb takes nothing returns nothing
    set globvar=1
    call ExecuteFunc("funa")
    set globvar=2
    call ExecuteFunc("funb")
endfunction

It will show 1 then 2

Code:
 function func takes nothing returns nothing
    set globvar=3
endfunction

function fund takes nothing returns nothing
    set globvar=0
    call ExecuteFunc("func")
    call BJDebugMsg(I2S(globvar))
endfunction

This will show 3.

The only problems will be when using waits between the ExecuteFunc and the part in the threaded func where you use the global, but that's solved by locals


Code:
 function DestroyEffect_Delayed takes nothing returns nothing
 local effect fx=bj_lastCreatedEffect
     call PolledWait(udg_EffectDur)
     call DestroyEffect(fx)
 set fx=null
endfunction

function Something takes nothing returns nothing
     call AddSpecialEffectBJ (bla blablbl ....)
     set udg_ EffectFuration=4
     call ExecuteFunc("DestroyEffect_Delayed")
endfunction

This will always destroy the effect after 4 seconds.

The only things that cause problems with values of global variables are Waits AND Trigger Registrations, or actions that may cause a Trigger's event to fire, if that Trigger changes the value of the global.

Otherwise it is safe
07-11-2005, 12:49 AM#5
SektorGaza
Quote:
I don't see how "every 0.10 seconds" would have a problem with game cache... unless the functions are so slow they take 0.1 seconds each... and I know they aren't that bad.

For some reason i can't stand periodic events, they look like a desync monster, specially if used throughout whole game. i do use them, just trying not to overuse them.

you are right cache shouldt cause problems with .1 periodic events, as long as it's not overused


p.s. you can use executefunction("func name") ? hurrr didn't know that, learned something new i guess ^_^
07-11-2005, 12:58 AM#6
Vexorian
I use 0.04 seconds periodic events and I don't see desyncs nor problems, of course if you mass them with gamecache usage that becomes a lag problem

I've always said that blizzardd should make a hash table type, so we could use it instead of gamecache, gamecache is slow because it was designed for hard drive saving
07-11-2005, 01:38 AM#7
SektorGaza
gamecashe is a hash table's retarted brother in a way. it's got similar functions, store some crap under unique id, access that crap directly, remove it, etc. .
although why do you say that it's used to save hd space? How do you know it works like that, just interested in your knowledge vex
07-11-2005, 02:45 AM#8
Heptameron
Quote:
Originally Posted by Lord Vexorian
The only type that doesn't work correctly with return bug is string, you should never use it with string, seriously, code, real ,boolean, and all the handle family work well.
So I assume a real is a single (four-byte), correct?

But otherwise that's good to hear. So even if function SomeFunction == function SomeFunction doesn't work I can just cast them to an integer first.

Quote:
Originally Posted by Lord Vexorian
The return bug It is not a bug actually, it is a Type cast method that is even used by blizzard.
The only place I've noticed it used is one place where the syntax checker at jass.sourceforge.net chokes on the Blizzard.j file... a real was returned from an integer function, or something. That's not really using it... or do you mean the Convert...() natives?

Quote:
Originally Posted by Lord Vexorian
Code:
 function funa takes nothing returns nothing
     call BJDebugMsg(I2S(globvar))
endfunction

function funb takes nothing returns nothing
    set globvar=1
    call ExecuteFunc("funa")
    set globvar=2
    call ExecuteFunc("[u]funb[/u]")
endfunction

It will show 1 then 2
Is that underlined part supposed to be funa? As near as I can see, executing that as-is would mean an infinite loop printing "1" over and over... why wouldn't it?

Otherwise it behaves like I hoped. Does this happen exactly the same if TriggerExecute() is used instead?

Quote:
Originally Posted by SektorGaza
although why do you say that it's used to save hd space? How do you know it works like that, just interested in your knowledge vex
Where did he say that? He just said it was designed for a use other than the one most people use it for now.
07-11-2005, 03:09 AM#9
SektorGaza
Quote:
I've always said that blizzardd should make a hash table type, so we could use it instead of gamecache, gamecache is slow because it was designed for hard drive saving
he said it, I guess i understand why it's designed for hd saving, so that massive campaigns could easily save/load whateva information needed.


p.s. the only thing I don't like in wc3 is the random number generator. I needed to generate randoms in a forgroup function and it pretty much gave the same number for every time it ran the function. maybe it's using gametime or timepassed, I think it's really not that random
07-11-2005, 02:01 PM#10
PitzerMike
Also be sure to check out this map http://www.wc3jass.com/files.php?mode=view&id=26

It shows quite a number of possibilities to start new threads and lists their advantages/disadvantages and characteristics.
Basically a sort of benchmark.
07-11-2005, 03:42 PM#11
Vexorian
Quote:
although why do you say that it's used to save hd space? How do you know it works like that, just interested in your knowledge vex

i said it was designed to be used to save data on hard drive, for campaigns and that stuff , it wasn't designed to be our hash table, and it is slow because of that.

Quote:
p.s. the only thing I don't like in wc3 is the random number generator. I needed to generate randoms in a forgroup function and it pretty much gave the same number for every time it ran the function. maybe it's using gametime or timepassed, I think it's really not that random
Test map uses fixed random number seed, unless you disable that in the prefferences dialog.

Quote:
Also be sure to check out this map http://www.wc3jass.com/files.php?mode=view&id=26

It shows quite a number of possibilities to start new threads and lists their advantages/disadvantages and characteristics.
Basically a sort of benchmark.
ExecuteFunc is the best because it doesn't require you to create new handles and remove them everytime
07-11-2005, 04:17 PM#12
Heptameron
Quote:
Originally Posted by Lord Vexorian
ExecuteFunc is the best because it doesn't require you to create new handles and remove them everytime
But both TriggerExecute() and TimerStart() offer comparatively elegant methods of passing parameters.

Ah well, looks like ExecuteFunc's my thing. Or a timer, if it's one-way. Thanks for the map, PitzerMike.

Just my question about embedded Blizzard.j left. Though my hopes aren't exactly high.
07-11-2005, 04:20 PM#13
Vexorian
I don't see what Timers have to do with this.

TriggerExecute is always a bad idea because of the TriggerAction leak
07-11-2005, 06:26 PM#14
Heptameron
Quote:
Originally Posted by Lord Vexorian
I don't see what Timers have to do with this.
They're a way to execute code, and handle vars work well with them...

Quote:
Originally Posted by Lord Vexorian
TriggerExecute is always a bad idea because of the TriggerAction leak
I've never heard of that leak. What is it?
07-11-2005, 11:41 PM#15
Vexorian
Well triggeractions leak.

timers are not threads since you can't use waits there., they are a way to execute code after a time which is something different from a thread.