Are variables thread safe in sclang?

Perhaps there should be a sclang facility equivalent to “disable interrupts”. After all, the main Thread of the REPL interpreter runs like this, meaning it’s impossible to yield from it without causing an error. So in that example if you could in a kind of pseudocode level::

  setStored { |newStored|
    var newSize = newStored.size;
    atomic {
      if (size != newSize) {
        onSizeUpdate.value()
        // an yield in any function called from there
        // would throw an Exception (say "yielded in atomic")
      };
      storedObject = newStorage;
   } // end atomic
  }

This is a bit inspired from Java’s synchronized keyword, but there’s no lock in this atomic.

Here is a little hacking experiment:

(r = Routine {
	var oldP = thisThread.parent.postln;
	thisThread.instVarPut(\parent, nil); // supa' hack
	thisThread.parent.postln;
	thisThread.instVarPut(\parent, oldP);
	thisThread.parent.postln;
})


r.run
// a Thread
// nil
// a Thread

So far so good for how atomic would be implemented. But if you actually try to yield while parent is nil.

(r = Routine {
	var oldP = thisThread.parent.postln;
	thisThread.instVarPut(\parent, nil); // supa' hack
	thisThread.parent.postln;
	// can't yield here; we're in "interrupts disabled" mode
	\huh.yield;
	thisThread.instVarPut(\parent, oldP);
	thisThread.parent.postln;
})


r.run // a Thread
//a Thread
//nil
//Interpreter has crashed or stopped forcefully. [Exit code: -1073741819]

The issue is that _RoutineYield assumes that a routine always has a non-nil parent. The only check is for the class. So basically Routines are Threads with non-nil parent, as I understand it.

But it’s a simple addition there to throw an error like “yielded with nil parent” to make our atomic hack work as intended. Actually the C++ code has a wee bit of copypasta there, so prRoutineAlwaysYield and prRoutineYieldAndReset would have to be changed similarly to check for nil parent… Interestingly, one of those had such a check but it’s commented out.