First of all, if you are trying to use the bool flag this way, you should mark it as volatile ( which is not recommended at all , but better than your code).
The second thing to note is that the lock statement is a sintax sugar for the Monitor methods of the class, so even if you were able to provide a value type for it (which, by the way, is a compilation error), two different threads will get their own version of the flag, making lock useless. Therefore, you must specify a reference type for the lock statement .
Thirdly, strings are immutable in C# , so it is theoretically possible for some method to keep the old string reference and execute lock in the wrong order. Alternatively, the string may become null from MainTextbox.Text in your case, which will run at run time, comparing to a private object that will never change (you should mark it as readonly way).
So, introducing a dedicated object for synchronization is the easiest and most natural way to separate the lock from the actual logic .
As for your source code, it has a problem since MainTextbox_TextChanged can override text that was not written. You can enter additional synchronization logic or use some library here. @Aron suggested Rx here, I personally prefer TPL Dataflow , it doesn't matter.
You can add the BroadcastBlock associated with the ActionBlock<string>(WriteCache) , which will remove the endless loop from the WriteCache and lock method from both of your methods:
var broadcast = new BroadcastBlock<string>(s => s); var consumer = new ActionBlock<string>(s => WriteCache(s)); broadcast.LinkTo(consumer);
VMAtm source share