Put concisely, threading is the idea of a single program executing multiple lists of instructions simultaneously or nearly simultaneously. A single list of instructions is a "thread": a string of instructions that flows from one to the next in order. Multi-threading, then, is just what we call a program that has multiple strings of instructions going on at the same time. A program can spend time following one thread, jump to another thread, and come right back to the original thread from where it left off. What's more is that any given thread does not have to know that the program jumped to another thread in order to keep working properly, making it much easier to write multi-threaded programs than it sounds.
It is not strictly necessary to know how threading works to write a multi-threaded program. But if you're curious about what's going on behind the scenes, read on!
In every multi-threaded program, there is a little chunk of code hiding in the background called the scheduler. It is the job of the scheduler to manage which thread the program should be working on at any given time. There are two major ways of scheduling: preemtively or cooperatively. Cooperative multi-threading will follow a single thread until that thread yields control. That is, it will keep with a particular thread until the thread itself decides that it's OK for another thread to take over. A cooperative scheduler waits for this yield then decides which thread to run next. On the other end of the spectrum is preemptive multi-threading. Preemptive schedulers will interrupt a thread if it decides that the thread was taking too long to yield, then jump to a new thread. Threads under a preemptive scheduler can also choose to yield on their own before they are preempted.
In Robot Mesh Studio, the schedulers for Blockly, Python, and C++ are preemptive. This means that you don't have to know which commands yield and which commands don't in order to write a successful multi-threaded program. That being said, it can be helpful to know exactly what's going on to avoid some potential small irregularities. For example, if a thread has not yielded for some time and starts updating values used by another thread, but gets interrupted by the scheduler before it finishes. Some of the values would have been updated, and others would still be waiting until the scheduler came back to the first thread. How to deal with potential problems with being preempted differs depending on programming language and implementation.
The threading functionality of Robot Mesh C++ allows for some fairly extensive control over user created threads, from setting priority, manipulating thread IDs, joining other threads (waiting for them to complete), stopping other threads, etc.
volatile keyword: Sometimes, code compilers take shortcuts to improve the speed of code. Occasionally, they take shortcuts that we don't want them to take. The volatile keyword (used in variable declarations: volatile type variable_name;) tells the compiler to not take shortcuts with a particular variable. This makes sure that multiple threads can access it and it will behave as expected. Global variables that will be used in multiple threads should be indicated to be volatile.
Thread class: Objects of this class represent threads of execution. They have a few interesting methods and a few uninteresting ones. The interesting ones are detailed below:
this_thread namespace: contains several static functions that return information about or perform operations on the thread they are called from.
Mutex class: a class of objects that any thread can try to lock but can only be unlocked by the thread that locked it. This is useful for creating sections of code that use shared resources, but can't tolerate other threads touching those shared resources while it is working with them. All uses of those resources could be hidden behind mutex locks to prevent interruption.