Software oscilloscope
The a) problem is trivial, I can't understand the b) problem.
Add a):
As you already mention a circular buffer, you will need a wr_pointer and rd_ponter. Now, when you update new sample, the wr_pointer is incremented in the ISR routine (FL): wr_pointer = (wr_pointer + 1) AND mask
buffer[wr_pointer] = ADC_value
wr_pointer = (wr_pointer + 1) AND mask 

When the (wr_pointer - rd_pointer) AND mask &gt;= 8 then you execute the SL, this can be done in main cycle, not need to have an additional ISR. You then read from buffer and increment the rd_pointer - only here. rd_pointer = (rd_pointer + 1) AND mask. The wr_pointer can change its value meantime, but it doesn't care.
if ((wr_pointer - rd_pointer) AND mask) &gt;=8{
    for .... 8 x read 8 sample
    {
       value[i] = buffer[rd_pointer]
      rd_pointer = (rd_pointer + 1) AND mask
    }
}

The mask is a size of buffer-1 , it's a power of 2. For example 8k bufer if 8192 cells, hence mask is 8191. At least that's how do I implement circular bufer.
The only caveat is that a wr_pointer shall be a variable type that is written all in one piece, for example a 8-bit MCU can split this into more values. It shall write the whole value in a single write.
EDIT:
ad 2)
You need to have a single whole buffer that has size of 2^N cells (power of two) to simplify the relative positions calculation with masking. You can calculate anything you want by simply using an &quot;AND mask&quot; operation after the arithmetic operation.
So let's assume that you have a SL thread that initially computes a sub-buffer of size 8, then in the middle of computation this is changed to 10:
 divisions_temp = divisions
 if ((wr_pointer - rd_pointer) AND mask) &gt;=divisions_temp{
    for 1 to divisions_temp  // read divisions_temp samples
    {
       value[i] = buffer[rd_pointer]
      rd_pointer = (rd_pointer + 1) AND mask
    }
}

The same rule applies here. You may need to put some semaphore if the variable is not written all in one piece - this may happen if this variable is received though a communication directly. But if it is received consistently, let's say the communication routine receives bytes and then fills a structure of variables, you can copy the whole struct to another one, when the comm. is complete and without errors - let the comm. routine is a different thread. You can even place a semaphore when you copy the struct and you clear it when the copy process is finished. You look for this semaphore in FL thread, before using divisions variable.
EDIT2:
But let' assume your processor is 32-bit and the array indexes as well the divisions variable is also 32-bit, then the CPU will write all these variables in a single instruction, no need to worry and use semaphores.