Scheduler and Sleep questions


I need non blocking independent processign of 2 tasks.
I'm working with board MKR NB 1500 which is SAMD21 microcontroller which is single core.
Although I understand c/c++ I'm still quite new in Arduino prigramming in general. As there is no real multithreadign I found Scheduler library

which does what I need but there is almost no information on how it works behind the scenes.
So I have some questions. I will appreciate if someone can expain a bit

  1. I figured out that if main loop() does not sleep (e.g. checking only time condition and allows processign only every some time), scheduler does not run any other parallel task it has registered. I assume that there is no CPU time left to switch to other tasks. On the other hand if I add just 10 ms delay() at the end of main loop, other tasks are running very well even though main loop is busy for several seconds on blocking tasks like sending data over cellular etc. So how does this work exactly? How is the cpu switching between tasks?

  2. I found volatile to make variables safe to modify with task outside of "control of the program" which I don't exactly understand what it is, in documentation interupt events are used as example. So are normal variables modified by concurent tasks managed by Scheduler dangerous? Should I use only volatile variables if they are modigied in 2 parallel tasks? Also question a bit related to question 1. If I use CircularBuffer to store messages, task 1 is sending messages to server from CircularBuffer. task 2 is watching some events and inserting new messages to same CircularBuffer. They are running in parallel. Can it happen that one task is looping buffer, and other is inserting to it? On real multithreading I would use semaphors to prevent this but can that happen with Scheduler task switching?

  3. I want to run on batteries so sleeping the device is crucial. I use LowPower library sleep() or deepSleep(). I've got 2 tasks which one is sending data to server and second is taking readings regularly from pins. data sending task can take longer, reading task is almost no time 1ms, it is periodic, every 1 sec. So when data sendign taks is not sendign data, readign task will put board to sleep for 1s after reading. Now when system wakes up, which of the tasks are run next? task1 (main loop) or task run by scheduler? if they are run parallel, then how much parallel? it may take a little time lets say 2 ms to find out if messages sending will happen so it can set flag to prevent reading task to put board to sleep. But if reading task will finish in 1ms it will put the board to sleep sooner than the other task realise it needs to do something.

I can put some delay() and allow some time before board is put to sleep. But I'd like to understand how it works to make it reliable and not waste more time outside of sleep then necessary.

It is kind of impossible to debug what is happening at ms level of timing with sleep() as the serial is disconnected over sleep.

Thanks for help.