Skip to content

Thread Safety

Alexandru Ciobanu edited this page Dec 14, 2022 · 3 revisions

Background

Sharpie, and its underlying NCurses library is inherently not thread-safe. Any two concurrent operations performed on Sharpie objects can result in undefined behavior. By default, when using Sharpie that is the behavior you get.

For example, assume the following (clearly illustrative) code:

using var terminal = new Terminal(NativeCursesProvider.Instance, new());

Task.Run(() => terminal.Screen.WriteText("Hello"));
Task.Run(() => terminal.Screen.WriteText("World"));
Task.Run(() => terminal.Screen.Refresh());

This code will likely result in strange artifacts on the screen as all three parallel tasks try to manipulate the screen simultaneously. Now, this is a very simple and obviously-avoidable example, but in sophisticated applications with multiple UI elements and modules, it is hard to maintain multi-threaded correctness.

Synchronized Run

This is where Terminal.Run comes into the picture. Application developers are encouraged to use this facility to transition the library into synchronized mode.

For example, the same code can be rewritten as:

using var terminal = new Terminal(NativeCursesProvider.Instance, new());

terminal.Run((t, e) => {
    if (e is StartEvent) 
    {
        t.Delegate(() => t.Screen.WriteText("Hello"));
        t.Delegate(() => t.Screen.WriteText("World"));
        t.Delegate(() => t.Screen.Refresh());
    }
    return Task.CompletedTask;
});

Yes, I know the example is not the best one, but what it shows is that Terminal.Run blocks the executing thread and executes all operations in a synchronized manner, thus avoiding any overlap and race conditions. The Terminal.Delegate method pushes an action to be executed in a synchronized manner.

Clone this wiki locally