Quality RTOS & Embedded Software

 Real time embedded FreeRTOS RSS feed 
Quick Start Supported MCUs PDF Books Trace Tools Ecosystem


Advice about accessing data (but not modifying) from another thread.

Posted by dibosco on November 10, 2015

I'm trying to understand what is good practice in terms of accessing data created/modified in another thread.

It seems that a queue is obviously the safest way of passing data from one thread to another, but what about when one thread merely needs to know about the status of somehting in another thread?

Is it acceptable to have an accessor function that reads a static variable in the module the other thread is contained in, to read and return, say, a flag?

For example:

I have a thread that parses an XML file and puts together which of the sixteen DALI scenarios are valid.

I have another thread that receives UDP packets in, with one of the fields in the UDP packet a request to switch to a new DALI scenario. If the DALI scenario is not valid, according to the XML thread, the scenario should not be requested over the DALI bus.

In this case, I have created a static variable in the XML parsing module that is a bit map, each bit set or cleared to define whether a scenario is valid. Is it acceptable for the UDP thread just to request that bit map and find out whether a particular scenario is valid? Or must I send that bit map to the UDP thread via a queue? If so. must, or should, that bit map be sent to the UDP thread or is it acceptable just to have a static variable accessible by the whole of the module that contains the UDP thread?

I have in the past (in other projects) had a queue of just length of one 32-bit variable - which is 32 flags - and just written to and read/peeked from/at that queue from lots of threads so all threads can at any time just look at the flags or read them out, modify them and restore them. In the end this is more of a faff. However, it may be that it is the only really thread-safe way of doing things?

Or is there a third way I have not thought of?

Having a separate queue for all different types of data for different threads to access like this soon really eats into precious RAM.

Many thanks :)

Advice about accessing data (but not modifying) from another thread.

Posted by heinbali01 on November 10, 2015

Hi DiBosco,

In most cases, I would share that kind of information without any protection, as long as it is clear that there is only one task allowed to change the data.

I'm sure you know about this potential optimisation problem:

~~~~~ extern BaseType_t isReady; /* Here it is not clear for the compiler that 'isReady' may be changed by another task. The test may be performed only once and the loop might never end. */ while( isReady == pdFALSE ) { // Do something }

/* This construction forces the compiler to fetch
'isReady' in every loop. */
while( *( ( volatile BaseType_t * )&isReady ) == pdFALSE )
	// Do something


But normally, all variables that you test will be fetched when required. The loop here above would be an exception.

If your data may also be changed by an interrupt, you'll need a critical section.

~~~~~ taskENTERCRITICAL() // change the data isReady = isReady + 1; taskEXITCRITICAL(); ~~~~~

The interrupt which changes the data does not need a critical section, because the interrupt normally won't get interrupted by an interrupt touching the same data.

If your data may only be changed by another task (not by an interrupt), you may suspend the scheduler:

~~~~~ vTaskSuspendAll(); // change the data isReady = isReady + 1; xTaskResumeAll(); ~~~~~

If changing the data is an atomic action (i.a. a single assembler instruction), no protection is needed.

~~~~~ /* 'isready' is accessed by a single instruction. */ isReady = 0; ~~~~~

But as said, in your application the common data is managed by a single task, so it doesn't need any protection.


Advice about accessing data (but not modifying) from another thread.

Posted by richard_damon on November 10, 2015

Hein, the answer to the optimization problem is to mark the variable 'volatile', which is designed to prevent this type of optimization and require the compiler to access the variable fresh each time it is used (Some C Purest will point out that volatile might not be quite enough, as it might not force cache coherency, but this is normally only a problem on multi-processor systems, for which FreeRTOS really isn't designed).

As to accessing the data, as long as you can make the accesses act 'atomic' then there is no problem. If only one thing writes to the data, and it is a simple small variable, this is normally not a big problem. If not, then you will need some sort of protection to make the actions act atomic. This can be critical sections, stoping the scheduler, or using a mutex/semaphore depending on the need.

Advice about accessing data (but not modifying) from another thread.

Posted by dibosco on November 11, 2015

Thanks folks, that's most helpful :)

[ Back to the top ]    [ About FreeRTOS ]    [ Sitemap ]    [ ]

Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.

Latest News

Meet us at Embedded World. Hall 3A-525.

Hear from Richard Barry at Embedded World. Feb 28, 16:00, Hall 4-428.

Video: Watch James Gosling & Richard Barry at re:Invent, Las Vegas 2017.

FreeRTOS kernel V10.0.1 is available for immediate download. Now MIT licensed.

FreeRTOS Partners

ARM Connected RTOS partner for all ARM microcontroller cores

IAR Partner

Microchip Premier RTOS Partner

RTOS partner of NXP for all NXP ARM microcontrollers

STMicro RTOS partner supporting ARM7, ARM Cortex-M3, ARM Cortex-M4 and ARM Cortex-M0

Texas Instruments MCU Developer Network RTOS partner for ARM and MSP430 microcontrollers

OpenRTOS and SafeRTOS