Nice, thanks!! You can probably guess which one, showing threads, that I prefer :-)) Mike
_____ From: Rony G. Flatscher [mailto:rony.flatsc...@wu.ac.at] Sent: 06 February 2024 10:47 To: oorexx-devel@lists.sourceforge.net Subject: [Oorexx-devel] Brief explanations on ooRexx' multithreading capabilities and the desired sample outputs (Re: Mike's suggestion added (Re: Another updated version for testing (Re: An updated version available (Re: Ad debugging multithreaded programs, a wor On 05.02.2024 17:07, Mike Cowlishaw wrote: There is a new version to * incorporate Mike's suggestion of inserting the thread number into the trace prefix after the second character, the option is 'T' (for thread), * a new (artificial) program that creates many threads such that the different formats can be compared ("docpgm.rex") by supplying the option (defaults to N, possible in addition T[hread], S[tandard], F[ull]) and the number of objects (defaults to 1) to create, Any sample outputs? Curious to see how it looks, even though I don't really have a use for it :-). Here we go. First a few remarks on multithreading in ooRexx: * to use multithreading is very easy in ooRexx, it is realized via messages that can be sent * synchroneously (the default, the sender waits until the message got processed in full, i.e. the invoked method routine ends and returns) or * asynchroneously (the message gets sent on a new thread, the sender continues immediately), * the ooRexx root class .Object has a "send" and "start" method that allows to submit the name of a message as a string (e.g. from a variable) from which a message object gets created and the message dispatched using "send" or "start" respectively, * there is a REPLY keyword statement available in method routines that will return to the sender/caller, but the remaining statements of that method routine will continue to get executed on a separate thread, * messages in ooRexx are represented with the .Message class which defines a method "send" for synchroneously and "start" for asynchroneously (on a separate thread) sending messages. The message object can be used to see whether e.g. an asynchroneous message is still running, but also what result a message delivered (cf. rexxref.pdf, "5.1.2. Message Class"), * there is an .Alarm class (cf. rexxref.pdf, "5.4.1. Alarm Class") that can be used to send a message at a later time on a separate thread, * if a method routine is guarded (the default) then it can only execute if it possesses the object lock, * if a method routine is unguarded it can always execute, * there is a "GUARD" keyword statement that can be used on synchronizing different method routines on different threads, controlling whether an object lock needs to be acquired (GUARD ON, GUARD ON WHEN ...) or whether an object lock gets released (GUARD OFF, GUARD OFF WHEN ...) such that other, currently blocked method routines can gain the object lock and continue to execute. The following test program is written such that it creates many threads on which Rexx code executes (to simulate as much as possible real world, complex multithreaded programs, e.g. in the context of powerful GUIs especially in the Java world, like JavaFX). The test program uses all of the above possibilities to also allow tracing their effects and demonstrating how the different formats help gain insight. Here an edited (updated) version of the program named "docpgm.rex", which can be invoked with the trace option and a number indicating how many objects should be created (the more objects the more threads): /* this is an artificial program that creates many threads */ parse upper arg option rounds if option<>"" then .traceObject~option=option say ".traceObject~option:" .traceObject~option if rounds="" then rounds=1 do counter c rounds say "round #" c"/"rounds obj=.demoMT~new -- from now on send messages asynchroneously (on separate threads) obj~~start("mg")~~start("mu")~~start("bumpCtlAttribute") msg=.message~new(obj,"bumpCtlAttribute") -- message to send later waitTime=.timeSpan~fromLongTime("00:00:0" || random(15,25)/1000) -- wait a few msecs -- commenting the following two statements will cause deadlocks .alarm~new(waitTime, msg) -- send message after waitTime, will unblock .alarm~new(waitTime, msg) -- send message after waitTime, will unblock end ::class "demoMT" -- a class for experimenting with threads ::method init -- guarded method expose ctlAttribute ctlAttribute=random(0,125)/1000 -- add some randomness ::method bumpCtlAttribute unguarded -- unguarded method expose ctlAttribute TRACE n -- set trace to normal (in method "bumpCtlAttribute") do 50 -- change value of ctlAttribute 50 times ctlAttribute=random(100,250)/1000 -- add some randomness end ctlAttribute=1 -- make sure a value that unblocks say .line "ctlAttribute="ctlAttribute ::method mg -- guarded method expose ctlAttribute guard off -- guard off reply -- return, remainder on new thread guard on when ctlAttribute>0.250 -- guard on ctlAttribute=random(0,125)/1000 -- add some randomness call sysSleep random(1,10)/1000 -- add some randomness guard off when ctlAttribute>0.250 -- guard off ctlAttribute=random(0,125)/1000 -- add some randomness say .context~name": returning ..." ::method mu unguarded -- unguarded method expose ctlAttribute guard on -- guard on reply -- return, remainder on new thread guard off when ctlAttribute>0.250 -- guard off ctlAttribute=random(0,125)/1000 -- add some randomness guard on when ctlAttribute>0.250 -- guard on call sysSleep random(1,10)/1000 -- add some randomness say .context~name": returning ..." ::options trace r Here the output of running the program as: "rexx docpgm.rex" 2 *-* parse upper arg option rounds >>> "" >>> "" >>> "" 3 *-* if option<>"" >>> "0" 4 *-* say ".traceObject~option:" .traceObject~option >>> ".traceObject~option: N" .traceObject~option: N 5 *-* if rounds="" >>> "1" 5 *-* then 5 *-* rounds=1 >>> "1" 7 *-* do counter c rounds >K> "COUNTER" => "0" >K> "FOR" => "1" >K> "COUNTER" => "1" 8 *-* say "round #" c"/"rounds >>> "round # 1/1" round # 1/1 9 *-* obj=.demoMT~new >I> Method "INIT" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 22 *-* expose ctlAttribute 23 *-* ctlAttribute=random(0,125)/1000 -- add some randomness >>> "0.014" >>> "a demoMT" 11 *-* obj~~start("mg")~~start("mu")~~start("bumpCtlAttribute") 12 *-* msg=.message~new(obj,"bumpCtlAttribute") -- message to send later >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >>> "a Message" 26 *-* expose ctlAttribute 35 *-* expose ctlAttribute 46 *-* expose ctlAttribute 13 *-* waitTime=.timeSpan~fromLongTime("00:00:0" || random(15,25)/1000) -- wait a few msecs 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 36 *-* guard off -- guard off 47 *-* guard on -- guard on >>> "a TimeSpan" 37 *-* reply -- return, remainder on new thread 48 *-* reply -- return, remainder on new thread 15 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 16 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock 38 *-* guard on when ctlAttribute>0.250 -- guard on 49 *-* guard off when ctlAttribute>0.250 -- guard off 17 *-* end >K> "WHEN" => "1" >K> "WHEN" => "1" 7 *-* do counter c rounds 50 *-* ctlAttribute=random(0,125)/1000 -- add some randomness 39 *-* ctlAttribute=random(0,125)/1000 -- add some randomness >>> "0.088" >>> "0.056" 51 *-* guard on when ctlAttribute>0.250 -- guard on 40 *-* call sysSleep random(1,10)/1000 -- add some randomness >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 26 *-* expose ctlAttribute 26 *-* expose ctlAttribute 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 >K> "WHEN" => "0" 32 ctlAttribute=1 >K> "WHEN" => "1" 52 *-* call sysSleep random(1,10)/1000 -- add some randomness >>> "0" 41 *-* guard off when ctlAttribute>0.250 -- guard off >K> "WHEN" => "1" 42 *-* ctlAttribute=random(0,125)/1000 -- add some randomness >>> "0.003" 43 *-* say .context~name": returning ..." >>> "MG: returning ..." MG: returning ... >>> "0" 53 *-* say .context~name": returning ..." >>> "MU: returning ..." MU: returning ... Clearly, the threads on which each statement executes would become interesting and in case of a deadlock important. --- Here Mike's minimal change to the trace prefix available in the portable debug version of ooRexx for Windows at <https://wi.wu.ac.at/rgf/rex/tmp/20240128_mt/> <https://wi.wu.ac.at/rgf/rex/tmp/20240128_mt/>. The command in this case is "rexx "rexx docpgm.rex t" (the argument "t" stands for thread): 2 *-* parse upper arg option rounds >>> "T" >>> "T" >>> "" 3 *-* if option<>"" >>> "1" 3 *-* then 3 *-* .traceObject~option=option 4 *-1* say ".traceObject~option:" .traceObject~option >>1> ".traceObject~option: T" .traceObject~option: T 5 *-1* if rounds="" >>1> "1" 5 *-1* then 5 *-1* rounds=1 >>1> "1" 7 *-1* do counter c rounds >K1> "COUNTER" => "0" >K1> "FOR" => "1" >K1> "COUNTER" => "1" 8 *-1* say "round #" c"/"rounds >>1> "round # 1/1" round # 1/1 9 *-1* obj=.demoMT~new >I1> Method "INIT" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 22 *-1* expose ctlAttribute 23 *-1* ctlAttribute=random(0,125)/1000 -- add some randomness >>1> "0.095" >>1> "a demoMT" 11 *-1* obj~~start("mg")~~start("mu")~~start("bumpCtlAttribute") 12 *-1* msg=.message~new(obj,"bumpCtlAttribute") -- message to send later >I2> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I3> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I4> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >>1> "a Message" 26 *-2* expose ctlAttribute 35 *-3* expose ctlAttribute 46 *-4* expose ctlAttribute 13 *-1* waitTime=.timeSpan~fromLongTime("00:00:0" || random(15,25)/1000) -- wait a few msecs 27 *-2* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 36 *-3* guard off -- guard off 47 *-4* guard on -- guard on >>1> "a TimeSpan" 37 *-3* reply -- return, remainder on new thread 48 *-4* reply -- return, remainder on new thread 15 *-1* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock >I2> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I3> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 16 *-1* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock 38 *-2* guard on when ctlAttribute>0.250 -- guard on 49 *-3* guard off when ctlAttribute>0.250 -- guard off 17 *-1* end >K3> "WHEN" => "1" >K2> "WHEN" => "1" 7 *-1* do counter c rounds 50 *-3* ctlAttribute=random(0,125)/1000 -- add some randomness 39 *-2* ctlAttribute=random(0,125)/1000 -- add some randomness >>3> "0.07" >>2> "0.079" 51 *-3* guard on when ctlAttribute>0.250 -- guard on 40 *-2* call sysSleep random(1,10)/1000 -- add some randomness >>2> "0" >I4> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". >I5> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". 41 *-2* guard off when ctlAttribute>0.250 -- guard off 26 *-4* expose ctlAttribute 26 *-5* expose ctlAttribute >K2> "WHEN" => "0" >K3> "WHEN" => "0" 27 *-4* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 27 *-5* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 >K2> "WHEN" => "0" 32 ctlAttribute=1 >K3> "WHEN" => "0" >K2> "WHEN" => "1" >K3> "WHEN" => "1" 42 *-2* ctlAttribute=random(0,125)/1000 -- add some randomness 52 *-3* call sysSleep random(1,10)/1000 -- add some randomness >>2> "0.086" 43 *-2* say .context~name": returning ..." >>2> "MG: returning ..." MG: returning ... >>3> "0" 53 *-3* say .context~name": returning ..." >>3> "MU: returning ..." MU: returning ... --- Here the "S"tandard multithreaded trace prefix version, running "rexx "rexx docpgm.rex s" (the argument "s" stands for standard): 2 *-* parse upper arg option rounds >>> "S" >>> "S" >>> "" 3 *-* if option<>"" >>> "1" 3 *-* then 3 *-* .traceObject~option=option [T1 I1 ] 4 *-* say ".traceObject~option:" .traceObject~option [T1 I1 ] >>> ".traceObject~option: S" .traceObject~option: S [T1 I1 ] 5 *-* if rounds="" [T1 I1 ] >>> "1" [T1 I1 ] 5 *-* then [T1 I1 ] 5 *-* rounds=1 [T1 I1 ] >>> "1" [T1 I1 ] 7 *-* do counter c rounds [T1 I1 ] >K> "COUNTER" => "0" [T1 I1 ] >K> "FOR" => "1" [T1 I1 ] >K> "COUNTER" => "1" [T1 I1 ] 8 *-* say "round #" c"/"rounds [T1 I1 ] >>> "round # 1/1" round # 1/1 [T1 I1 ] 9 *-* obj=.demoMT~new [T1 I2 G L0 ] >I> Method "INIT" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T1 I2 G L1 *] 22 *-* expose ctlAttribute [T1 I2 G L1 *] 23 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [T1 I2 G L1 *] >>> "0.104" [T1 I1 ] >>> "a demoMT" [T1 I1 ] 11 *-* obj~~start("mg")~~start("mu")~~start("bumpCtlAttribute") [T1 I1 ] 12 *-* msg=.message~new(obj,"bumpCtlAttribute") -- message to send later [T2 I3 G L0 ] >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T3 I4 U L0 ] >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T4 I5 U L0 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T1 I1 ] >>> "a Message" [T2 I3 G L1 *] 35 *-* expose ctlAttribute [T3 I4 U L1 ] 46 *-* expose ctlAttribute [T4 I5 U L1 ] 26 *-* expose ctlAttribute [T1 I1 ] 13 *-* waitTime=.timeSpan~fromLongTime("00:00:0" || random(15,25)/1000) -- wait a few msecs [T2 I3 G L1 *] 36 *-* guard off -- guard off [T3 I4 U L1 ] 47 *-* guard on -- guard on [T4 I5 U L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 [T1 I1 ] >>> "a TimeSpan" [T2 I3 G L0 ] 37 *-* reply -- return, remainder on new thread [T3 I4 U L1 *] 48 *-* reply -- return, remainder on new thread [T1 I1 ] 15 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock [T4 I3 G L1 ] >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T2 I4 U L1 *] >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T1 I1 ] 16 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock [T4 I3 G L1 ] 38 *-* guard on when ctlAttribute>0.250 -- guard on [T2 I4 U L1 *] 49 *-* guard off when ctlAttribute>0.250 -- guard off [T1 I1 ] 17 *-* end [T2 I4 U L1 ] >K> "WHEN" => "1" [T4 I3 G L1 *] >K> "WHEN" => "1" [T1 I1 ] 7 *-* do counter c rounds [T2 I4 U L1 ] 50 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [T4 I3 G L1 *] 39 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [T2 I4 U L1 ] >>> "0.072" [T4 I3 G L1 *] >>> "0.051" [T2 I4 U L1 ] 51 *-* guard on when ctlAttribute>0.250 -- guard on [T5 I6 U L1 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T3 I7 U L1 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [T4 I3 G L1 *] 40 *-* call sysSleep random(1,10)/1000 -- add some randomness [T5 I6 U L1 ] 26 *-* expose ctlAttribute [T3 I7 U L1 ] 26 *-* expose ctlAttribute [T5 I6 U L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") [T3 I7 U L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") [T2 I4 U L1 *] >K> "WHEN" => "0"32 ctlAttribute=1 [T2 I4 U L2 *] >K> "WHEN" => "1" 32 ctlAttribute=1 [T2 I4 U L2 *] 52 *-* call sysSleep random(1,10)/1000 -- add some randomness [T4 I3 G L2 *] >>> "0" [T4 I3 G L2 *] 41 *-* guard off when ctlAttribute>0.250 -- guard off [T4 I3 G L1 ] >K> "WHEN" => "1" [T4 I3 G L1 ] 42 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [T4 I3 G L1 ] >>> "0.024" [T4 I3 G L1 ] 43 *-* say .context~name": returning ..." [T4 I3 G L1 ] >>> "MG: returning ..." MG: returning ... [T2 I4 U L1 *] >>> "0" [T2 I4 U L1 *] 53 *-* say .context~name": returning ..." [T2 I4 U L1 *] >>> "MU: returning ..." MU: returning ... The legend in the bracketed part: "T" ... thread, "I" ... invocation, "G" or "U" method was defined as guarded or unguarded, "L" ... object Lock count, "*" possessing the object's lock. --- Here the "F"ull multithreaded trace prefix version, running "rexx "rexx docpgm.rex f" (the argument "f" stands for full): 2 *-* parse upper arg option rounds >>> "F" >>> "F" >>> "" 3 *-* if option<>"" >>> "1" 3 *-* then 3 *-* .traceObject~option=option [R1 T1 I1 ] 4 *-* say ".traceObject~option:" .traceObject~option [R1 T1 I1 ] >>> ".traceObject~option: F" .traceObject~option: F [R1 T1 I1 ] 5 *-* if rounds="" [R1 T1 I1 ] >>> "1" [R1 T1 I1 ] 5 *-* then [R1 T1 I1 ] 5 *-* rounds=1 [R1 T1 I1 ] >>> "1" [R1 T1 I1 ] 7 *-* do counter c rounds [R1 T1 I1 ] >K> "COUNTER" => "0" [R1 T1 I1 ] >K> "FOR" => "1" [R1 T1 I1 ] >K> "COUNTER" => "1" [R1 T1 I1 ] 8 *-* say "round #" c"/"rounds [R1 T1 I1 ] >>> "round # 1/1" round # 1/1 [R1 T1 I1 ] 9 *-* obj=.demoMT~new [R1 T1 I2 G A1 L0 ] >I> Method "INIT" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T1 I2 G A1 L1 *] 22 *-* expose ctlAttribute [R1 T1 I2 G A1 L1 *] 23 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [R1 T1 I2 G A1 L1 *] >>> "0.089" [R1 T1 I1 ] >>> "a demoMT" [R1 T1 I1 ] 11 *-* obj~~start("mg")~~start("mu")~~start("bumpCtlAttribute") [R1 T1 I1 ] 12 *-* msg=.message~new(obj,"bumpCtlAttribute") -- message to send later [R1 T2 I3 G A1 L0 ] >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T3 I4 U A1 L0 ] >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T4 I5 U A1 L0 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T1 I1 ] >>> "a Message" [R1 T2 I3 G A1 L1 *] 35 *-* expose ctlAttribute [R1 T3 I4 U A1 L1 ] 46 *-* expose ctlAttribute [R1 T4 I5 U A1 L1 ] 26 *-* expose ctlAttribute [R1 T1 I1 ] 13 *-* waitTime=.timeSpan~fromLongTime("00:00:0" || random(15,25)/1000) -- wait a few msecs [R1 T2 I3 G A1 L1 *] 36 *-* guard off -- guard off [R1 T3 I4 U A1 L1 ] 47 *-* guard on -- guard on [R1 T4 I5 U A1 L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") 32 ctlAttribute=1 [R1 T1 I1 ] >>> "a TimeSpan" [R1 T2 I3 G A1 L0 ] 37 *-* reply -- return, remainder on new thread [R1 T3 I4 U A1 L1 *] 48 *-* reply -- return, remainder on new thread [R1 T1 I1 ] 15 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock [R1 T4 I3 G A1 L1 ] >I> Method "MG" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T2 I4 U A1 L1 *] >I> Method "MU" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T1 I1 ] 16 *-* .alarm~new(waitTime, msg) -- send message after waitTime, will unblock [R1 T4 I3 G A1 L1 ] 38 *-* guard on when ctlAttribute>0.250 -- guard on [R1 T2 I4 U A1 L1 *] 49 *-* guard off when ctlAttribute>0.250 -- guard off [R1 T1 I1 ] 17 *-* end [R1 T3 I6 U A1 L1 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T2 I4 U A1 L1 ] >K> "WHEN" => "1" [R1 T4 I3 G A1 L1 *] >K> "WHEN" => "1" [R1 T1 I1 ] 7 *-* do counter c rounds [R1 T3 I6 U A1 L1 ] 26 *-* expose ctlAttribute [R1 T2 I4 U A1 L1 ] 50 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [R1 T4 I3 G A1 L1 *] 39 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [R1 T3 I6 U A1 L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") [R1 T2 I4 U A1 L1 ] >>> "0.12" 32 ctlAttribute=1 [R1 T4 I3 G A1 L1 *] >>> "0.075" [R1 T2 I4 U A1 L1 ] 51 *-* guard on when ctlAttribute>0.250 -- guard on [R1 T4 I3 G A1 L1 *] 40 *-* call sysSleep random(1,10)/1000 -- add some randomness [R1 T5 I7 U A1 L1 ] >I> Method "BUMPCTLATTRIBUTE" with scope "demoMT" in package "G:\test\orx\trace\docpgm.rex". [R1 T5 I7 U A1 L1 ] 26 *-* expose ctlAttribute [R1 T5 I7 U A1 L1 ] 27 *-* TRACE n -- set trace to normal (in method "bumpCtlAttribute") [R1 T2 I4 U A1 L1 *] >K> "WHEN" => "0" 32 ctlAttribute=1 [R1 T2 I4 U A1 L2 *] >K> "WHEN" => "1" [R1 T2 I4 U A1 L2 *] 52 *-* call sysSleep random(1,10)/1000 -- add some randomness [R1 T4 I3 G A1 L2 *] >>> "0" [R1 T4 I3 G A1 L2 *] 41 *-* guard off when ctlAttribute>0.250 -- guard off [R1 T4 I3 G A1 L1 ] >K> "WHEN" => "1" [R1 T4 I3 G A1 L1 ] 42 *-* ctlAttribute=random(0,125)/1000 -- add some randomness [R1 T4 I3 G A1 L1 ] >>> "0.04" [R1 T4 I3 G A1 L1 ] 43 *-* say .context~name": returning ..." [R1 T4 I3 G A1 L1 ] >>> "MG: returning ..." MG: returning ... [R1 T2 I4 U A1 L1 *] >>> "0" [R1 T2 I4 U A1 L1 *] 53 *-* say .context~name": returning ..." [R1 T2 I4 U A1 L1 *] >>> "MU: returning ..." MU: returning ... The legend in the bracketed part: "R" ... interpreter instance (needed in complex deployments like ooRexx JavaFX programs or in ooRexx JSP - Java Server Pages - deployments), "T" ... thread, "I" ... invocation, "G" or "U" method was defined as guarded or unguarded, "A" attribute pool (each object has a different one), "L" ... object Lock count, "*" possessing the object's lock. In this relatively simple run only one object gets used such that we only see a single attribute pool ("A1"). Once one uses more (and in complex multithreaded applications there may be even hundred of hundreds such objects) objects, the attribute pool becomes extremely helpful to quickly identify the traces of a specific object (which may play a role in a deadlock situation). --- To illustrate I created the four standard formats for a test run of the above program using three objects, i.e. "rexx docpgm.rex n 3", "rexx docpgm.rex t 3", "rexx docpgm.rex s 3", and "rexx docpgm.rex f 3" and attach them to this message. --- The current .TraceObject implementation allows in addition to easily define one owns trace format and e.g. use the TIMESTAMP- and NR-entries in them (for sorting, analyzing timings, etc.). Also, the tracutil.cls package includes routines to save traces as json and cvs files (and recreate traceobject collections from such json and csv files) such that they can be analyzed with (Rexx) programs or loaded into Excel and analyze the trace there with the available means, and much more. HTH, ---rony
_______________________________________________ Oorexx-devel mailing list Oorexx-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/oorexx-devel