Welcome to our new forum
All users of the legacy CODESYS Forums, please create a new account at account.codesys.com. But make sure to use the same E-Mail address as in the old Forum. Then your posts will be matched. Close

Thread Safe Objects

Anonymous
2012-10-04
2015-04-08
  • Anonymous - 2012-10-04

    Originally created by: rickj

    Is it possible to create threads safe objects or function blocks?

    Consider a simple key-value container object consisting of two arrays named key and value respectively. An AddItem(key, value) method searches the key array until it finds an empty element. When the first empty element is found the specified key and value data is written to empty key element and the specified value is written to the corresponding value element.

    A problem comes if the dictionary is shared between two or more tasks. A low priority task can find an empty element and be preempted before it is able to write to the element. If a higher priority task then calls AddItem() it will also find the same empty element and fill it. When the higher priority task finishes the lower priority task will continue and immediately overwrite the higher priority task's data.

    I am looking for a means of making the find and fill operations atomic so that task preemption (by other user tasks) cannot occur between these operations.

    This is usually accomplished using disable/enable preemption functions before and after the critical instructions. Many systems also provide a preemption threshold so that tasks with a priority higher than the threshold will not be affected.

    What mechanisms are available in CoDCeSys and it's various flavors? If not available is it possible to make such functions in an external C library; are there enough hooks and documentation to do so reliably?

    Thanks

     
  • sarathbabu - 2012-10-09

    Hi,
    Have you tried IECtask lib it can help you on this.

    Thanks

     
  • Strucc - 2012-12-04

    I think SysLibSem is the relevant answer for your question. Each time, you would like to write shared data, just lower the semaphore - it's safely shared among tasks.

     
  • Anonymous - 2012-12-05

    Originally created by: rickj

    I really can't see the point of using a semaphore; if you have a rationale I would like to hear it.

    What is needed is the ability to make several instructions atomic (i.e. uninterruptable). The two instructions I have in mind test a pointer array element for null and if null writes a valid pointer to the element. Using this technique it's not necessary to repeatedly attempt the operation until it succeeds. You make one call and it succeeds period.

    Now consider how the semaphore mechanism works. It also has the same requirement for atomic instructions. Therefore it necessarily must disable/enable task preemption for several instructions, the same as described above. Using a semaphore provides no additional benefit and unnecessarily complicates the usage of the library functions that utilize them. A library function that requires additional code around it's call for thread safety, is itself not thread safe.

    Dose anyone know how to access CoDeSys's disable/enable task preemption functionality in structured text language?

     
  • Strucc - 2012-12-05

    I can see your point, but I don't know a way to create "atomic" code segments in CoDeSys. Could be a useful function, that's right... But this is mostly a 61131-3 standard related issue...

    As for semaphores: I don't know the "physical" representation of CoDeSys tasks, if they are threads, processes or... just a bunch of code running after each other (probably platform dependent). BUT, in theory it's possible that 2 tasks are running at the same time. This means, that just by checking then setting a "locking" variable (memory location) is not safe... 2 tasks can do this at the same time, both of them doing the checking and getting positive confirmation before actually "locking". Semaphore is a safe construct to use for this purpose. (Also syslock... But I don't know if it's implemented in CoDeSys)

    What you can do with semaphores is to jump trough part of code if blocked by another task, and retry it in the next cycle.

     
  • Anonymous - 2012-12-05

    Originally created by: rickj

    Zitat:
    What you can do with semaphores is to jump trough part of code if blocked by another task, and retry it in the next cycle.

    Right, that's exactly my point. "Retry the next cycle" is an additional code requirement external to a library object. This means the library object is itself not thread safe and that it can be made safe by using external code. Semaphores are appropriate for synchronizing external asynchronous processes and are not an appropriate means of achieving atomicity of code.

    If your were thinking in an object oriented way you would clearly see how quickly this becomes impractical.

    Zitat:
    ... I don't know a way to create "atomic" code segments in CoDeSys

    Well, since the semaphore mechanism requires atomicity of several instructions to function correctly it is obviously implemented by CoDeSys. I would just like to know how it's done. Seems to me to be an infinitely reasonable question.

    Zitat:
    But this is mostly a 61131-3 standard related issue...

    In what way? I am not aware that 61131-3 places any functionality restrictions on vendor provided function blocks such as "vendor shall not provide capability to disable/enable task preemption".

    Thank you for the conversation

     
  • shooter - 2012-12-07

    put a flag before you add, if flag is true do not add another, false the flag when added, then the next can give it a try.

     
  • shooter - 2012-12-07

    it is also no good practice to have something set in two places.
    same as for an output when this is done in two places it is asking for big debug problems.

     
  • Strucc - 2012-12-09

    shooter hat geschrieben:
    put a flag before you add, if flag is true do not add another, false the flag when added, then the next can give it a try.

    This doesn't work, it's not "thread safe" (the task can be interrupted between checking and setting the flag).

    I see the reason behind this, and also the reason to build a thread safe dictionary object. And believe me I'm thinking in an OOP way... sometimes a bit too object-oriented for CoDeSys Many of us have C or C++ coding practice, and it's nice to see similar features in CoDeSys, but IEC-61131-3 requires slightly different approach than regular application programming...

    About the practice of not writing the same variables from different places: this is true for IEC variables, mostly "%Q". But here, we are talking about a function block, that can be called from multiple tasks, multiple locations.

    Back to the question, in CoDeSys V3 you have:
    CAA.TaskLock();
    CAA.TaskUnlock();
    These calls are blocking, so be careful with them.

    Between these two calls the above mentioned "flag" could be checked and set. Just make sure, that this flag is not used anywhere else... (should be a global, (or static), used only by this FB/Object). For "standard" non-blocking resource management use CAA.SEMA, or CAA.BOLT.

    As for the "thread safety" of these "library calls": they are intended to be used for synchronization purposes, I don't know how the CoDeSys compiler does that, but hopefully it does correctly.

     
  • Strucc - 2012-12-09

    rickj hat geschrieben:
    In what way? I am not aware that 61131-3 places any functionality restrictions on vendor provided function blocks such as "vendor shall not provide capability to disable/enable task preemption".

    What I meant was that there are no ATOMIC / END_ATOMIC statements defined in the standard. Therefore this functionality can only be reached by RTS specific library calls. Once again, I don't know how the compiler deals with them... but it must somehow

     
  • Anonymous - 2012-12-10

    Originally created by: rickj

    Strucc,

    Thanks, I believe this is what I was looking for.

    Zitat:
    Back to the question, in CoDeSys V3 you have:
    CAA.TaskLock();
    CAA.TaskUnlock();
    These calls are blocking, so be careful with them.

    Btw, just in case any CoDeSys folks are listening in on this discussion: You should consider allowing TaskLock to take a priority threshold parameter. Tasks with a priority higher than the threshold would then not be prevented from preempting and running. It's a fairly common technique.

     
  • Strucc - 2015-02-15

    Were these calls removed from the current CoDeSys libraries?

    CAA.TaskLock();
    CAA.TaskUnlock();

    Do I really have to use semaphores?

     
  • Strucc - 2015-04-08

    Would be nice to hear some reflections from the "officials" on these issues too...

     

Log in to post a comment.