Do variables need to be 'locked' with PC comms?

Experts,

I have a PC application that is talking with the Arduino. Everything is fine. In the multi-threaded world of the PC, we have to worry about variables being written to and read at the same time.

How likely is this same concern to crop up with Arduino MCU operation?

TIA!

It depends what interrupts you have active, how they interact with the variables, and the size of the variables.

"variables being written to and read at the same time.

How likely is this same concern to crop up with Arduino MCU operation?"

I'd say not at all - there is only processor, it can only do one thing at a time over the single bus where variables are accessed.

The code may write into a register, then an interrupt my occur and overwrite that same register before the original write had a chance to be read elsewhere Coding on your part can prevent that without much effort I would imagine.

holesflow:
Experts,

I have a PC application that is talking with the Arduino. Everything is fine. In the multi-threaded world of the PC, we have to worry about variables being written to and read at the same time.

How likely is this same concern to crop up with Arduino MCU operation?

TIA!

"at the same time" is not really the proper terminology even on a the PC.
What is a concern is Atomicity.
The ability to do a full operation to completion without interruption.
This can occur any time there are multiple threads of operation that can be interrupted or pre-empted by a thread that is accessing or modifying the same piece of data.
When using a real OS this can happen when there are multiple processors or even on a single processor whenever there are context switches to different tasks or threads.

So from a conceptual perspective there is no difference on the issue between a PC running an OS or an Arduino

In the simplistic Arduino environment this can happen if you are modifying data or h/w registers in two different operational threads. The only way you can have multiple operational threads in Arduino is to be doing something in the main sketch and then in an ISR function.

Depending on what you are doing, the atomicity protection needed can vary slightly or require multiple protection mechanisms.
The sketch code (foreground) can mask interrupts to lock out the ISR.
But also if accessing/sharing a variable with ISR code you will have to declare the variable volatile to notify the compiler so that the compiler will not attempt to keep the contents in a register but rather to always flush out its contents back to RAM to ensure that another operational thread can see the latest contents of the variable.
You may have to do both as there can be cases where even simple operations like var++ are interruptible.
For example, on the AVR, a int is 16 bits but the processor is only 8 bits.
If you declare your integer variable volatile that will ensure that contents are always updated back to RAM.
However, since the processor is only 8 bits, the processor cannot do the increment in RAM atomically. Because of this, you must mask interrupts to protect the operation from the ISR since an interrupt could happen right in the middle of the increment operation and the ISR could end up seeing a variable in an invalid state.

All these concepts and issues are identical to what can happen on a PC running an OS.

--- bill

holesflow:
How likely is this same concern to crop up with Arduino MCU operation?

Yet another XY problem.

Tell us what you actually want to do and then you should get a useful answer. Speculating about every possible thing that might or might not happen seems a waste of time.

Maybe have a look at Serial Input Basics

...R

@AWOL,

Thanks for writing. My application is quite simple. Instead of burdening the forum with speculation, as I have no ill symptoms, I was hoping to find if this kind of situation was possible. In .NET, for example, we can lock parts of code, variables, or entire class instances for ensuring what @bperrybap accurately describes as atomicity.

I'm fluent with C++, but not enough so to understand whether it is subject to the kind of interrupt/event program flow other languages are.

As noted, I do not have a failed situation, or example code to recreate a problem. I'm really just curious about the language, I guess... That's why I asked how likely it might be. :slight_smile:

AWOL:
It depends what interrupts you have active, how they interact with the variables, and the size of the variables.

This type of problem is not language dependent as the same issues occur regardless of language the code was written.

The issue is the same for Arduino as it is for an application running in any other environment on any OS, Windows, Linux, etc...

It all comes down to can the code be interrupted and pre-empted by other code?
And if so, does the code that interrupts and pre-empts share data/variables with the code being interrupted?
And if so, will seeing or doing partial updates of the data/variables be an issue?
If so, then some sort of atomicity lockout mechanism must be used.

All that said, since there is no pre-emptive scheduling in Arduino, there are only two threads.
Foreground and ISR.

So, if you aren't writing any code that shares variables with code that runs in an ISR, you won't have the issue because all the code you are writing is in a single operational thread running in the foreground.

Once you start to use code that runs in an ISR context (using interrupts or libraries that call your code from their ISR) you will have to be concerned since the ISR context can interrupt and pre-empt your foreground code.

If you are not using interrupts or libraries that use interrupts that call your code from an ISR, you won't have any issues.

--- bill

@bill,

Thanks for writing. I want to stress that I am no expert in C/C++ or MCU programming. I’ve been in electronics and computers for decades, but am new to this exciting aspect with Arduino.

While it has frustrated Robin2, I have been up front about asking whether it is an issue to deal with. Working code would not seem to advance the discussion, unless I could create a problem.

bperrybap:
“at the same time” is not really the proper terminology even on a the PC.
What is a concern is Atomicity.
The ability to do a full operation to completion without interruption.

Exactly. And one way around it in generic programming would be transactions. If the ATMega structure isn’t capable of multi-threading (as you make note of in your reply) in most normal uses, then there is probably no issue.

bperrybap:
In the simplistic Arduino environment this can happen if you are modifying data or h/w registers in two different operational threads. The only way you can have multiple operational threads in Arduino is to be doing something in the main sketch and then in an ISR function.

I’ll read up on this (starting here)! Thanks!

bperrybap:
Depending on what you are doing, the atomicity protection needed can vary slightly or require multiple protection mechanisms.

I figured it was an ‘it depends’ issue. Thanks for shedding light on it.

bperrybap:
For example, on the AVR, a int is 16 bits but the processor is only 8 bits.
If you declare your integer variable volatile that will ensure that contents are always updated back to RAM.
However, since the processor is only 8 bits, the processor cannot do the increment in RAM atomically.

I’ve read a bit on this in this related thread here.

bperrybap:
Because of this, you must mask interrupts to protect the operation from the ISR since an interrupt could happen right in the middle of the increment operation and the ISR could end up seeing a variable in an invalid state.

Thanks for pointing me in the right direction to research!

holesflow:
If the ATMega structure isn't capable of multi-threading (as you make note of in your reply) in most normal uses,

It isn't that the ATMega part isn't capable of doing multi-threading or tasking, it is that that the Arduino environment is very simplistic and does not support or provide for multi-threading or tasks.
In Arduino, there is a single foreground task and interrupts happen which call ISR functions that can run and interrupt that foreground code.

In terms of the actual embedded and C/C++ environment here is summary of what happens at startup:
The bootloader starts at reset/powerup.
It runs the compiled sketch code that has been uploaded.
In the compiled sketch code

  • C startup code runs first which sets up the stack some variables and then calls main()
  • Arduino provides a main() function
  • main() first calls your setup() function
  • after setup() returns, main() loops forever calling loop()

The users sketch code all runs under the loop() function.
It is a single thread and a single call stack.
The call stack can get deep depending on the code and how many functions & subfunctions it calls but it is still a single thread/context.
When loop() returns, it returns back to main() which calls loop() again.

ISRs run in the background when interrupts come in.
At a minimum there is a 1 ISR running that bumps the millis() counter.
Other libraries can use interrupts. Examples of this are servo and infrared libraries.
There are also some timer libraries that can call a user specified function after the specified time. Those you have be careful with as your code is called directly from the timer library ISR function, so it is interrupting the foreground.
Also, since it is running in an ISR, you have to minimize the time in that function since it is blocking all other interrupts and there are certain services that will not be available in that function since it is running at ISR level.

--- bill

holesflow:
While it has frustrated Robin2, I have been up front about asking whether it is an issue to deal with.

You could probably go through a lifetime of PC programming without every having to deal with multi-threading and variables being written and read at the same time.

When you have an application that requires multi-threading (as some of mine do) you need to manage that appropriately. But IMHO you manage it in a way that is specific to the project you are dealing with (even if the concepts are general).

Also a microprocessor is a very different environment from a PC so that concepts that are taken for granted in PC programming with Gigabytes of memory and GHz of performance may not be at all appropriate.

I enquired about the Arduino project you want to implement so that advice can be focused on the problem - rather than trying to solve every problem in the known and unknown universe. For all we know you are worrying about something that will never present a problem for your project. Alternatively, you may have in mind a project that is impractical on a microprocessor.

...R

Robin2:
You could probably go through a lifetime of PC programming without every having to deal with multi-threading and variables being written and read at the same time.

When you have an application that requires multi-threading (as some of mine do) you need to manage that appropriately. But IMHO you manage it in a way that is specific to the project you are dealing with (even if the concepts are general).

Fair enough. I appreciate your insight.