When to use copy-by-reference and when to use copy-by-value

avivf wrote on Sunday, October 07, 2018:

Hi,
Is there some “finger rule” regards data size to be copied by value and data size to be copied by reference?
How can I know when to use each the copy types upon sending a message?

Thanks,
Aviv

heinbali01 wrote on Sunday, October 07, 2018:

What do you mean with “sending a message”? Do you refer to the FreeRTOS queues?

If it’s about the FreeRTOS queues, my answer would be: it depends on the size of the object that you are passing.
When you are passing integer numbers, I would send their values.
But as soon as the objects are bigger that let’s say a pointer ( 32 or 64 bytes ), I would pass a reference to the object.

It is important of course to think about the ownership of those objects. The objects must exist until they are passed to the receiver. The receiver must somehow free them.

avivf wrote on Wednesday, October 10, 2018:

Hi,
Thanks for answer.

What I’m looking for is an advice regards working with FreeRTOS queues (upon sending a message): When to use copy-by-reference and when to use copy-by-value.

In FreeRTOS website is written that it’s designed to work efficiently with copy-by-value:

The FreeRTOS queue usage model manages to combine simplicity with flexibility - attributes that are normally mutually exclusive. Messages are sent through queues by copy, meaning the data (which can be a pointer to larger buffers) is itself copied into the queue rather than the queue always storing just a reference to the data. This is the best approach because:
Small messages that are already contained in C variables (integers, small structures, etc.) can be sent into a queue directly. There is no need to allocate a buffer for the message and then copy the variable into the allocated buffer. Likewise, messages can be read from queues directly into C variables

(Taken from: [https://www.freertos.org/Embedded-RTOS-Queues.html])

Yet, would like to know what’s a reasonable data size for copy-by-value. Bigger size will use copy-by-reference.

Thanks,
Aviv

richarddamon wrote on Wednesday, October 10, 2018:

Basic answer, it depends. In essence, a FreeRTOS queue will ALWAYS use copy-by-value, as that is how the queue operation is defined, the only question becomes what is the ‘value’ to be copied, is it the structure, or is it just a pointer to the structure. If to send just a pointer, you are going to have to copy the data anyway into a specialaly allocated buffer to be sent, then you might not get that much savings by trying to use a copy-by-reference, as you are still needing to copy the whole structure anyway.

Practically, Ifind it tends to work out to be fairly clear. A structure with only 2 or 3 sinple values is fairly efficient to copy, so directly putting that into a queue is reasonable. A structure with a sizable array is not. There is a middle ground that you have to think more about, and the answer there tends to come down to how hard is it going to be to be to make the data START (and then stay) in a suitable buffe, as if I will be copying it anyway, might as well let the queue do the copy.

If it is easy to naturally start off with a set of buffers that move through the system as pointers, then you can shift to that method for even fairly small sized buffers. If it isn’t then the switch over point gets pushed bigger. If the size of the data is significantly variable, then sending a pointer can make more sense as queue deal with fixed sized objects (but a Message Buffer might be appropriate(.

rtel wrote on Wednesday, October 10, 2018:

I’m afraid there is no generic answer to that as it depends on how much
RAM you have in your system, how long the queue needs to be, and how
efficiently your system can move memory (if you are using a small 8-bit
it is likely to be inefficient but you won’t have much RAM anyway, if
you were using a Cortex-A then it is likely to be very efficient). As
the page you reference explains, copy by value is much simpler to use,
results in fewer bugs as you don’t have to remember to return buffers or
decide who owns any particular buffer, and allows you to pass data
across memory protection boundaries - all those things are reasons to
favour copy by value if you can - so as a general rule of thumb I would
say if your system has enough RAM to hold everything in a queue by
value, and the performance of your system allows it (that is, it does
break your system if you try copying memory around, although memory copy
is normally very efficient these days), then use copy by value. If you
start to run out of RAM then look at how large your queues are - if the
space they consume is large enough to make a difference if you were to
remove them, then convert them to copy by reference.

This is all very generic advice though - I know it sounds like a cop out
but it is really very dependent on each individual use case.

heinbali01 wrote on Wednesday, October 10, 2018:

Here is an example often used in FreeRTOS+TCP to pass messages to the IP-task:

typedef struct
{
    eIPEvent_t eEventType;
    void *pvData;
} IPStackEvent_t;

It is a struct of 8 bytes ( or more on a 64-bit CPU ), and it is passed by value.

In following example, it is created on stack and passed to the queue of the IP-task:

    IPStackEvent_t xNetworkDownEvent = { eNetworkDownEvent, NULL };
    xReturn = xQueueSendToBack( xNetworkEventQueue, &( xNetworkDownEvent ), xTimeout );

The queue knows that the object is 8 bytes long. The contents will be copied with memcpy.

It would be less convenient and less efficient to allocate 8 bytes space and pass that by address:

    IPStackEvent_t *pxNetworkDownEvent = (IPStackEvent_t *)pvPortMalloc( sizeof ( IPStackEvent_t ) );
    if( pxNetworkDownEvent != NULL )
    {
        pxNetworkDownEvent->eEventType = eNetworkDownEvent;
        pxNetworkDownEvent->pvData = NULL;
        xReturn = xQueueSendToBack( xNetworkEventQueue, pxNetworkDownEvent, xTimeout );
    }