Author Topic: Coding style for atomic execution  (Read 996 times)

0 Members and 1 Guest are viewing this topic.

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Coding style for atomic execution
« on: April 14, 2021, 10:28:52 pm »
Hi,
is there a preferred style when writing code like the one below? Out of the two options, which one is the preferred and why?

I personally always use the first one which creates an additional variable but it has a 1:1 match of the Enter/ExitCritical.
taskENTER_CRITICAL(); and taskEXIT_CRITICAL(); are freeRTOS functions to lock INTs for critical sections like ensuring atomic code execution.

First Option...:

            taskENTER_CRITICAL();  //stops all INTs
            tmpVar = xVarToTestAtomically;  //xVarToTestAtomically is not the core's native data type so accessing it is not an atomic operation
            taskEXIT_CRITICAL();    //restarts all INTs

            if (tmpVar)
            {
                ExitThisFunctionRightHere();
            }
            DoSomethingElse();

Second option...:

            taskENTER_CRITICAL();  //stops all INTs
            if (xVarToTestAtomically) //xVarToTestAtomically is not the core's native data type so accessing it is not an atomic operation
            {
                taskEXIT_CRITICAL(); //restarts all INTs
                ExitThisFunctionRightHere();
            }
            taskEXIT_CRITICAL();    //restarts all INTs
            DoSomethingElse();

Thank you :)
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 6337
  • Country: fr
Re: Coding style for atomic execution
« Reply #1 on: April 14, 2021, 10:37:29 pm »
The first option is obviously cleaner and less error-prone, but beyond that, it's also more efficient if whatever you need to do with the variable takes some time, as the critical section only blocks for the time it takes to copy the variable.
 
The following users thanked this post: ricko_uk

Offline langwadt

  • Super Contributor
  • ***
  • Posts: 2397
  • Country: dk
Re: Coding style for atomic execution
« Reply #2 on: April 14, 2021, 10:45:47 pm »
The first option is obviously cleaner and less error-prone, but beyond that, it's also more efficient if whatever you need to do with the variable takes some time, as the critical section only blocks for the time it takes to copy the variable.

and you can wrap it up in a define (or inline function)
 
The following users thanked this post: ricko_uk

Online lucazader

  • Regular Contributor
  • *
  • Posts: 175
  • Country: nz
Re: Coding style for atomic execution
« Reply #3 on: April 14, 2021, 10:52:30 pm »
You could probably look in the C atomic types. (available since c11)
lots of different data types in there as well as the ability to create your own atomic structs etc.

https://en.cppreference.com/w/c/atomic

This should emit the relevant instructions on any platform that you run on to ensure the atomic nature of the variable you are interested in.
 
The following users thanked this post: newbrain, Jacon, I wanted a rude username, ricko_uk

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Re: Coding style for atomic execution
« Reply #4 on: April 15, 2021, 12:22:12 am »
Thank you all :)
 

Offline mikerj

  • Super Contributor
  • ***
  • Posts: 2709
  • Country: gb
Re: Coding style for atomic execution
« Reply #5 on: April 15, 2021, 12:24:22 am »

taskENTER_CRITICAL(); and taskEXIT_CRITICAL(); are freeRTOS functions to lock INTs for critical sections like ensuring atomic code execution.


Be careful, on an Arm Cortex micro these only disable interrupts with a priority at or below configMAX_SYSCALL_INTERRUPT_PRIORITY i.e. interrupts that can call RTOS API functions.  Higher priority interrupts will still be running.
 

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Re: Coding style for atomic execution
« Reply #6 on: April 15, 2021, 02:59:14 am »
Thank you Mikerj :)
 

Offline jc101

  • Frequent Contributor
  • **
  • Posts: 376
  • Country: gb
Re: Coding style for atomic execution
« Reply #7 on: April 15, 2021, 05:08:37 pm »
If you are looking to compare a variable in one task, but you may be altering it in another task, would it be better to wrap the access with a mutex (binary semaphore in FreeRTOS)?

Created with xSemaphoreCreateMutex, then you take it with xSemaphoreTake and give it back with xSemaphoreGive when you're done.
 

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Re: Coding style for atomic execution
« Reply #8 on: April 15, 2021, 11:37:16 pm »
Thank you jc101,
newbie to RTOS. What is the difference between my approach and the one you suggest? I'm not familiar with mutex/semaphores.

Thank you
 

Offline newbrain

  • Super Contributor
  • ***
  • Posts: 1101
  • Country: se
Re: Coding style for atomic execution
« Reply #9 on: April 16, 2021, 07:51:17 am »
What is the difference between my approach and the one you suggest?
The major difference is that entering a critical section with taskENTER_CRITICAL() will stop any other activities or tasks going on at the same time (with the caveat explained by mikerj), in practice the RTOS is suspended until taskEXIT_CRITICAL().

This mean that also tasks that do not depend on that specific variable are blocked, independent from their priority.

In very general terms, the less and shorter critical sections, the better.

Taking and releasing a mutex or semaphore, instead, will only affect the two involved tasks.

If you are a using an RTOS, semaphores, mutexes, queues are something you should get familiar with, FreeRTOS has an oldish but still relevant tutorial book, with plenty of examples and explanations.
Nandemo wa shiranai wa yo, shitteru koto dake.
 

Offline jc101

  • Frequent Contributor
  • **
  • Posts: 376
  • Country: gb
Re: Coding style for atomic execution
« Reply #10 on: April 16, 2021, 05:43:53 pm »
Thank you jc101,
newbie to RTOS. What is the difference between my approach and the one you suggest? I'm not familiar with mutex/semaphores.

Thank you

As stated in another post, using a mutex doesn't stop the whole system whilst giving you the behaviour of exclusive access to something when you need it.  Mutex is Mutually Exclusive access to something.

The FreeRTOS website has lots of well commented examples for the basic features.  The books here are worth reading https://www.freertos.org/Documentation/RTOS_book.html


 

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Re: Coding style for atomic execution
« Reply #11 on: April 17, 2021, 12:19:25 pm »
Thank you newbrain and jc101 :)
 

Offline peter-h

  • Frequent Contributor
  • **
  • Posts: 546
  • Country: gb
  • Doing electronics since the 1960s...
Re: Coding style for atomic execution
« Reply #12 on: April 18, 2021, 12:56:59 pm »
Why is there no simple DI / EI ?

I know one problem with "EI" is that it would re-enable interrupts even if they were disabled, which would prevent a generic function to be called from both "EI" code and "DI" code, but you could easily detect the int enable status (on the Z80 it was an intentional side effect of one instruction) and re-enable ints only if they were previously enabled.
Z80 Z180 Z280 Z8 S8 8031 8051 H8/300 H8/500 90S1200 32F417
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 3730
  • Country: fi
Re: Coding style for atomic execution
« Reply #13 on: April 18, 2021, 02:40:04 pm »
Why is there no simple DI / EI ?

That is an option but the OP intentionally wants to use an RTOS and the whole point of OS is to abstract away hardware, providing higher-level and consistent interfaces.

I personally think this line of thought is overrated because many of the "useful abstractions" are borrowed from non-RT OSes which again work against the long history and highly variable hardware of general purpose computing, where uniform standards are a necessity, and committees coming up with standards such as POSIX are the necessary evil. The end result is, code written for RTOS tends to take longer to write, is longer, adds overhead and prevents using of some features present in the microcontroller, and finally, doesn't necessarily offer the portability the designers wanted.

The proof is in the examples; the OP used the RTOS abstractions, but somehow come to the conclusion that adding a comment that describes what actually happens on the low level, is necessary. I don't blame them.

As you say, on microcontrollers, atomic execution can be as simple as disabling and enabling interrupts. Parallelism is also, in most cases, extremely simple, to the point that constructing a typical "parallel" MCU application using interrupts comes easier than learning just the syntax to use things like pthreads, or any interface an RTOS provides. Of course, in some more complex cases, doing everything from scratch becomes more work, but MCU projects usually aren't that complex.

Personally, I'm not a big fan of abstracting away atomic accesses to "automate" the re-enabling of interrupts to the existing state; the motivation is such automation will allow nesting atomic operations, encouraging you to use such operations anywhere because it's "easier" and "safer". No, atomic operations and disabling/enabling interrupts temporarily, in my mind, is a special operation which always happens with care and consideration, and is documented using comments. So then I just disable and re-enable the interrupts, and don't allow myself to create a complex condition where I don't know if the interrupts were already disabled and should not be re-enabled.

Low level programming on microcontrollers is a strength, not a hindrance, and I don't like abstracting it away. Desktop computing is different.
« Last Edit: April 18, 2021, 02:44:07 pm by Siwastaja »
 
The following users thanked this post: peter-h

Offline ricko_uk

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: gb
Re: Coding style for atomic execution
« Reply #14 on: April 20, 2021, 06:11:57 pm »
Thank you Siwastaja :)
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf