2

When should I use locks using freertos on something like cortex-m3? It seems to be clear using multicore systems but what about single core?

For example I have two tasks. In first I increment variable named counter. Second task saves current value of that variable when some event occurs. Should I use locks here? May first task corrupt value which second task is saving?

Long Smith
  • 1,339
  • 3
  • 21
  • 40

3 Answers3

3

Yes, you should use locks to protect access to the shared resource.

You can't be sure that the sequence generated by the compiler to read the shared variable is atomic, so it might be unsafe.

If you want to be a bit more hard-core, possibly gaining performance, you can use various ways to actually ensure that the variable can be accessed atomically. See comment.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • There`s `_Atomic` plus `stdatomic.h` with macros which types are guaranted contention-free atomic. On an ambedded system `_Static_assert`ing the types used are atomic is well acceptable. – too honest for this site Apr 15 '16 at 13:51
  • @Olaf so I can use `stdatomic.h` from newlib without any tricks? – Long Smith Apr 15 '16 at 14:14
  • @LongSmith: `stdatomic.h` is not part of the newlib, but typically the compiler. See the standard. – too honest for this site Apr 15 '16 at 15:14
  • For stdatomic.h to work properly, the operating system needs to support it. For example, any ARM port of FreeRTOS would have to execute CLREX or a dummy STREX when a context switch between tasks occurs. When I last checked, this wasn't implemented. But it also depends on the port. So be careful! – Sven May 08 '21 at 21:45
2

You need use locks to synchronize concurrent access to shared objects, the easiest scenario would be like:

lock_t l; // defines a lock of your system

// thread 1:
lock(l);
counter += 1;
unlock(l);


// thread 2:
lock(l);
do_something(counter);
unlock(l);
fluter
  • 13,238
  • 8
  • 62
  • 100
1

In your specific example where there is one reader and one writer (so not in the "general" case, and definitely not in the case where there are multiple writers) then I would suggest a lock is not need if the variable being written/read is the natural word size of the architecture, and is needed if the variable is not the natural word size of the architecture.

In your case the word size is 32-bits, so if the variable is a uint32_t then it will be updated atomically, and one writer and multiple readers is safe. If on the other hand the variable were a uint64_t then it will be updated (written to) in two separate accesses, and you must ensure the reader does not access the variable in between the two updates as to do so would be to read a corrupted (half updated) value.

In FreeRTOS a simple way of doing this would be to use a basic critical section thus:

taskENTER_CRITICAL();
My64BitVariable++;
taskEXIT_CRITICAL();

The best method though depends on the frequency of the event. If the event is "not too fast", then why not send the value from one task to another using a queue, in which case FreeRTOS takes care of all the concurrency issues for you. Better (faster and less RAM) still, depending on what the receiving task is doing, have the writing task send the value to the receiving task directly using a direct to task notification.

Richard
  • 3,081
  • 11
  • 9