Shop OBEX P1 Docs P2 Docs Learn Events
Need more info about Locks — Parallax Forums

Need more info about Locks

AGCBAGCB Posts: 327
edited 2015-03-24 14:39 in Propeller 1
I've tried searching for a tutorial on using locks but not found one that explains in more depth.

My main interest at the present is how (if possible) to lock 1 hub variable while letting other variables be free to be changed.

I'm building a programmable room thermostat and want to be able to HOLD the temperature, overriding the auto program. There are things that need to continue while in HOLD like LCD display etc. which use hub ram.

Your suggestions are valued.

Thanks
Aaron

Comments

  • AGCBAGCB Posts: 327
    edited 2015-03-23 03:11
    I may have discovered answers in the "similar Threads" block at the bottom of my post. I need to research more. Thanks.
  • Mark_TMark_T Posts: 1,981
    edited 2015-03-23 04:42
    Its up to you how you use the locks, so yes you can lock one particular variable using one lock if you want.

    You have a choice of dynamically allocating them (locknew, lockret) or statically by number. If you want
    to play nice with objects that might also use locks, then dynamically allocate at initialization...

    There are only 8 locks, so be aware of that limitation.
  • kuronekokuroneko Posts: 3,623
    edited 2015-03-23 04:55
    Mark_T wrote: »
    If you want to play nice with objects that might also use locks, then dynamically allocate at initialization...
    @AGCB: If you go down that road note that locknew doesn't guarantee a specific lock state. While all locks are cleared after reset, it's perfectly valid to return a set lock (which is then presented during the next locknew).
  • AGCBAGCB Posts: 327
    edited 2015-03-23 05:05
    Mark_T wrote: »
    , so yes you can lock one particular variable using one lock if you want.

    You have a choice of dynamically allocating them (locknew, lockret) or statically by number. If you want
    to play nice with objects that might also use locks, then dynamically allocate at initialization...

    I think I will use a flag instead but for future reference and learning, how can I specify only locking one variable?

    Also, what do you mean by dynamically or statically?

    @kuroneko
    Would you explain that for dummies
  • Mark_TMark_T Posts: 1,981
    edited 2015-03-23 05:07
    You use the lock - where you want to use it. So use it around access to that variable.

    I mean the same as everyone else when I say dynamic and static, runtime v. compile time.
  • kuronekokuroneko Posts: 3,623
    edited 2015-03-23 05:24
    AGCB wrote: »
    Would you explain that for dummies
    Usually you find code like this:
    SemID := locknew
    
      ..
    
      repeat while lockset(SemID)
    
      ' stuff
    
      lockclr(SemID)
    
    Which simply means that with an unset lock (from locknew) the code above has the chance to run stuff immediately. OTOH, if the lock returned by locknew (reuse case) is still set you'd have to wait until it's explicitly cleared by some other thread or - depending on your program structure - you'll sit there forever, e.g. if you start another cog with the same code structure both of them will just sit there.

    I'm only mentioning it as I've seen it fail like this. Your code/usage may be robust enough so that this doesn't matter.
  • evanhevanh Posts: 15,920
    edited 2015-03-23 05:27
    Mark_T wrote: »
    Its up to you how you use the locks, ...

    Aaron,
    That's a key point. Locks, by themselves, do not lock the actual data. They only have function when used by cooperating routines that are written to exclusively attempt access of the "lock"ed data only when the lock is acquired. What that means is your cooperating routines enter blocking states while waiting to acquire the relevant lock and only continue when the lock is acquired.

    The purpose of a lock is to provide a way to prevent multiple concurrent accesses on a group of data from multiple tasks. This allows one task to change all the required details without another task getting confused. This is know as an atomic operation.

    If only one integer is of concern then a lock is not the droid you are looking for.
  • evanhevanh Posts: 15,920
    edited 2015-03-23 05:38
    What you are likely wanting to do is have an IF condition in the temperature updating routine that tests a flag for go/stop and skips the temperature update accordingly.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2015-03-23 05:39
    If your program has a HOLD state, keep that variable in the hub so you can read that from the cogs that could make changes. If the hold state is true, don't make changes. As Evan pointed about, locks are simply flags -- you still have to decide what to do with them.
  • evanhevanh Posts: 15,920
    edited 2015-03-23 05:52
    evanh wrote: »
    The purpose of a lock is to provide a way to prevent multiple concurrent accesses on a group of data from multiple tasks. This allows one task to change all the required details without another task getting confused. This is know as an atomic operation.

    There is a common alternative to synchronising with locks; and that is double buffering and it's ilk. The various buffering solutions solve many timing issues and also add significant throughput benefits. Their downside is they consume memory, sometimes lots of memory.
  • edited 2015-03-23 09:41
    AGCB wrote: »
    I've tried searching for a tutorial on using locks but not found one that explains in more depth.

    My main interest at the present is how (if possible) to lock 1 hub variable while letting other variables be free to be changed.

    My understanding is that the locks don't actually 'lock' anything. They're flags that can be set programmatically to indicate that a hub variable is being manipulated by a process. This would prevent two processes from trying to change the same variables at the same time.

    Hub access prevents a variable from being accessed simultaneously by multiple cogs so my take on it is that they are useful in cases where multiple variables need to be updated and the result is only reliable when ALL variables have been updated.

    Sandy
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2015-03-23 10:24
    Hub access prevents a variable from being accessed simultaneously by multiple cogs so my take on it is that they are useful in cases where multiple variables need to be updated and the result is only reliable when ALL variables have been updated.
    Or when a single variable can be accessed by two processes via read/modify/writes.

    BTW, a hub variable as a flag cannot be a replacement for a lock. Locks are special flags that require only one hub access to check and set them. Variables take two.

    -Phil
  • evanhevanh Posts: 15,920
    edited 2015-03-23 13:07
    Or when a single variable can be accessed by two processes via read/modify/writes.

    Good point. The key part of this is both processes modify that one variable.

    EDIT:
    An alternative way to do this without a lock is have a third managerial task that hides the real variable storage and instead services requests from the other two tasks. Eg: Tasks one and two both want to add 1 to the variable so each issue the request of ADD with a value of +1 in their respective request buffers. Task three then checks each buffer in turn and modifies the real stored variable accordingly.

    To keep some order, the request mechanism would need a synchronising handshake. Something like a request flag to say a request is pending, this is held active until a separate replying acknowledge flag is activated. And likewise the acknowledging flag stays active until the request flag has deactivated.

    Importantly, each flag is written by only one task each, which means they can't be at the same word address. Shared writes cannot be if there is no hardware locks provided to facilitate them.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2015-03-23 14:35
    evanh wrote:
    The key part of this is both processes modify that one variable.
    Well, if that's all they did, it wouldn't be a problem -- say, if each process just wrote something there. The issue is that, in order to morph, rather than set, a value, you have to read it first. And it's that hub two-step that gets you into trouble.

    One could get around this by using the cnt register in conjunction with the cogid to allow a read/modify/write in quick succession only when the last n bits of cnt equal a certain value dictated by cogid. That way, you produce wider, non-overlapping windows that allow multiple hub accesses.

    -Phil
  • AGCBAGCB Posts: 327
    edited 2015-03-23 14:56
    So when the HOLD method is entered in this program, the "setTemperature" is held indefinitely. There are still things that need to happen like reading temperature sensors, updating LCD display and controlling the furnace etc. Some are in other cogs, some not. All these use hub variables. If the HOLD method locks the hub, how can anything else that uses hub ram work?

    Thanks
    Aaron
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2015-03-23 15:01
    You can't "lock the hub." All cogs have access to the hub all the time, in round-robin succession. A lock is just a gentlemen's agreement between two processes not to do certain things when the other process "owns" the lock. But that agreement is up to the programmer to design and enforce. The hardware doesn't enforce anything of the sort.

    -Phil
  • AGCBAGCB Posts: 327
    edited 2015-03-23 15:44
    Thanks for all the replies. One thing I know now is locks are not as easy to use as I thought they would be. And from the 'similar threads' below are probably not worth the bother. I did use them in a personal remake of DeSilva's 'locks' PASM tutorial and thought it worked fine.

    So thanks again
    Aaron
  • evanhevanh Posts: 15,920
    edited 2015-03-23 19:36
    ... in order to morph, rather than set, a value, you have to read it first. And it's that hub two-step that gets you into trouble.
    Ya, modify does imply that. I just didn't explicitly say it that way, since you already had, for brevity.

    One could get around this by using the cnt register in conjunction with the cogid to allow a read/modify/write in quick succession only when the last n bits of cnt equal a certain value dictated by cogid. That way, you produce wider, non-overlapping windows that allow multiple hub accesses.

    Nice! Excellent trick. CNT is simultaneously identical for all Cogs and is a single fast instruction away. I'd imagine that's not something every multiprocessor system has at it's disposal.
  • evanhevanh Posts: 15,920
    edited 2015-03-23 19:41
    AGCB wrote: »
    So when the HOLD method is entered in this program, the "setTemperature" is held indefinitely.

    Ah, the set temperature ... What exactly is changing the set temperature anyway? Isn't it just operator adjusted?
  • AGCBAGCB Posts: 327
    edited 2015-03-24 06:28
    Right.

    1st the set temperature is adjusted with an up or down button, then when the hold button is pressed, the program jumps to the infinite repeat hold method with each loop testing for the up button press which ends the loop and the program returns to the auto mode. The auto mode changes the set temperature according to the time of day(input from RTC). The hold method could run from hours to days. When in the hold program, the set temperature must not be reset by the auto program.

    Aaron
  • evanhevanh Posts: 15,920
    edited 2015-03-24 14:39
    It's best just to code the enhancement right into the routine that is to be affected. In this case the auto setpoint adjustment routine should additionally watch for a defined hold flag ... and not make the automatic adjustments while this hold flag is set.
Sign In or Register to comment.