Newbie - question regarding sharing of memory between cogs and compiler variabl
Garch
Posts: 3
Hi,
·
I am a newbie to the propeller and would very much appreciate some guidance re. sharing of memory between cogs. I have read the propeller manual and the beginners section of this forum. I have question regarding the global variable scope between separate objects and cogs. Please see example below.
·
·
ROOT OBJECT (Top most object)
·
VAR ··· LONG· sharedLong
·
OBJ ···· objectAInstance : "ObjectA" ,· objectBInstance : "ObjectB"
·
·
PUB MAIN
·
··········· objectAInstance.Start(sharedLong)········· ‘ by value; OR….
··········· objectAInstance.Start(@sharedLong)······ ‘ by reference
··········· objectBInstance.Start(@sharedLong)
···········
DAUGHTER OBJECT:
·
===== Filename = “ObjectA.spin” ======
·
·
VAR ··· LONG·· passedParameter, stack[noparse][[/noparse]30]
·
·
PUB Start(sharedLongParameter)
·
··········· Passedparameter := sharedLongParameter
··········· cognew(DoSomethingInACog, @stack)
·
·
PUB DoSomethingInACog | aMethodVariable
·
··· Repeat
··········· aMethodvariable := sharedLong + 1········ ‘ Read from memory
·
·
DAUGHTER OBJECT:
·
===== Filename = “ObjectB.spin” ======
·
·
VAR ··· LONG·· passedParameter, stack[noparse][[/noparse]30]
·
·
PUB Start(sharedLongParameter)
·
··········· Passedparameter := sharedLongParameter
··········· cognew(DoSomethingInACog, @stack)
·
·
PUB DoSomethingInACog | aMethodVariable
·
··· Repeat
··········· passedParameter := passedParameter + 1· ‘ Write to memory
·
···········
·
I am a newbie to the propeller and would very much appreciate some guidance re. sharing of memory between cogs. I have read the propeller manual and the beginners section of this forum. I have question regarding the global variable scope between separate objects and cogs. Please see example below.
·
- How does the compiler resolve the scope of a global variable defined in the root (top most) object and calls to reference that global variable in instanced daughter objects?
- Should the “top most” object pass-by-reference the global variable defined in it via a daughter’s method’s parameter?
- Should the “top most” object pass-by-value (ie a copy) the global variable defined in it via a daughter’s method’s parameter? I can’t see how this would work as you’d be passing a copy of the global variable into the temporary stack created when the daughter method is called, which would be lost when the method exited and the stack was unwound. ·
- Is the global variable in the “top most” object visible to all daughter object instances? If so, how is the “name” of the variable e.g. sharedLong, passed into scope of the daughter objects. Surely a daughter object cannot just reference “sharedLong” as it has not been defined within the daughter objects VAR declaration and the compiler won’t know what is being referenced.
- Is there a simpler way of achieving this that I am missing?
·
ROOT OBJECT (Top most object)
·
VAR ··· LONG· sharedLong
·
OBJ ···· objectAInstance : "ObjectA" ,· objectBInstance : "ObjectB"
·
·
PUB MAIN
·
··········· objectAInstance.Start(sharedLong)········· ‘ by value; OR….
··········· objectAInstance.Start(@sharedLong)······ ‘ by reference
··········· objectBInstance.Start(@sharedLong)
···········
DAUGHTER OBJECT:
·
===== Filename = “ObjectA.spin” ======
·
·
VAR ··· LONG·· passedParameter, stack[noparse][[/noparse]30]
·
·
PUB Start(sharedLongParameter)
·
··········· Passedparameter := sharedLongParameter
··········· cognew(DoSomethingInACog, @stack)
·
·
PUB DoSomethingInACog | aMethodVariable
·
··· Repeat
··········· aMethodvariable := sharedLong + 1········ ‘ Read from memory
·
·
DAUGHTER OBJECT:
·
===== Filename = “ObjectB.spin” ======
·
·
VAR ··· LONG·· passedParameter, stack[noparse][[/noparse]30]
·
·
PUB Start(sharedLongParameter)
·
··········· Passedparameter := sharedLongParameter
··········· cognew(DoSomethingInACog, @stack)
·
·
PUB DoSomethingInACog | aMethodVariable
·
··· Repeat
··········· passedParameter := passedParameter + 1· ‘ Write to memory
·
···········
Comments
In one object you can have object-global variables. You simply put that variable into a DAT section. So, for example when you have ObjectAInstance1 and ObjectAInstance2 they can share such a variable - even if both objects run in different COGs (when we talk about SPIN).
·
Just to confirm then, the following would work within spin? And there would be no resource conflicts (ie reading and writing simultaneously) due to the round-robin nature of the hub?
TOP MOST OBJECT:
VAR LONG sharedLong
OBJ objectAInstance : "ObjectA" , objectBInstance : "ObjectB"
PUB MAIN
objectAInstance.Start(@sharedLong) ‘ pass object global VAR by reference objectBInstance.Start(@sharedLong) ‘ pass object global VAR by reference
DAUGHTER OBJECT (Write Object)
===== Filename = “ObjectA.spin” ======
VAR LONG passedParameter, stack[noparse][[/noparse]30]
PUB Start(sharedLongParameter)
Passedparameter := sharedLongParameter
cognew(DoSomethingInACog, @stack)
PUB DoSomethingInACog | aMethodVariable
Repeat
long[noparse][[/noparse] passedParameter ] := long[noparse][[/noparse] passedParameter ] + 1 ‘ Write to shared memory
DAUGHTER OBJECT (Read Object)
===== Filename = “ObjectB.spin” ======
VAR LONG passedParameter, stack[noparse][[/noparse]30]
PUB Start(sharedLongParameter)
Passedparameter := sharedLongParameter
cognew(DoSomethingInACog, @stack)
PUB DoSomethingInACog | aMethodVariable
Repeat
aMethodVariable := long[noparse][[/noparse] passedParameter ] ‘ Read from shared memory
How is this part processed:
1. read content of the global variable
2. add 1
3. write back the new content
As it is in SPIN a lot of HUB-RAM access windows will have passed between read and write. So, what can happen?
a) In the current version the·read-only Object has a good chance to read the same value several times
b) Maybe it reads the value after step 1. but before 3.
c) If code of the modifying object is faster than the code of the reading object you might miss values.
If you have more complex data this might cause inconsistencies. For example if you have 2 longs that belong together - say a timestamp and a temperature. Object A updates these, Object B displays the data. So, if you don't synchronize the access, Object B might read the a combination where timestamp has already been updated, but the temperature is still the older temperature.
That's why the locks have been invented.
TOP MOST OBJECT:
VAR···· LONG· sharedLong
········· BYTE SemID
OBJ····· objectAInstance : "ObjectA" ,· objectBInstance : "ObjectB"
PUB MAIN
·if (SemID := locknew) == -1
··········· ‘ error, no locks available
else
······· objectAInstance.Start(@sharedLong, @SemID)······ ‘ pass object global VAR by reference·······················
······· objectBInstance.Start(@sharedLong, @SemID)····· ‘ pass object global VAR by reference···················
DAUGHTER OBJECT (Write Object)
===== Filename = “ObjectB.spin” ======
VAR···· LONG·· passedParameter, stack[noparse][[/noparse]30]
········· BYTE··· mySemID
PUB Start(sharedLongParameter, semIDparameter)
··········· Passedparameter := sharedLongParameter
··········· mySemID := semIDparameter
··········· cognew(DoSomethingInACog, @stack)
PUB DoSomethingInACog | aMethodVariable
··
··········· repeat until not lockset(@mySemID)
··········· long[noparse][[/noparse] passedParameter ] := long[noparse][[/noparse] passedParameter ] + 1· ‘ Write to shared memory
··········· lockclr (@mySemID)
·········
DAUGHTER OBJECT (Read Object)
===== Filename = “ObjectA.spin” ======
VAR···· LONG·· passedParameter, stack[noparse][[/noparse]30]
········· BYTE··· mySemID
PUB Start(sharedLongParameter, semIDparameter)
··········· Passedparameter := sharedLongParameter
··········· cognew(DoSomethingInACog, @stack)
PUB DoSomethingInACog | aMethodVariable·······
··········· repeat until not lockset(@mySemID)
··········· aMethodVariable := long[noparse][[/noparse] passedParameter ]····· ‘ Read from shared memory
··········· lockclr (@mySemID)
·