14: Synchronization - royal-lang/rl GitHub Wiki

Synchronization

Synchronization or mutexes are available in Royal using the sync keyword.

It's inherently made to avoid deadlocks etc. by allowing multiple objects to be locked etc.

sync // Global synchronization
{
}

sync (OBJECT) // Or just: sync object
{
}

sync (OBJECT1, OBJECT2)
{
}

Example:

sync
{
    sharedCounter++;
}

sync foo
{
    foo.update();
}

Avoiding deadlocks can be done by using multiple synchronization objects.

Wrong:

sync foo
{
    sync bar
    {
        foo.update(bar); // Possible deadlock
    }
}

Okay: (Royal will actually force this upon you if you attempt to directly synchronize another object.)

sync foo,bar
{
    foo.update(bar);
}

You can also set a ref struct to be synchronized which will make sure all functions in it are synchronized.

ref:sync struct Foo
{
    private:
    var decimal _bar;

    public:
    fn update()
    {
        _bar++;
    }
}

...

var foo @= Foo;

// Wrong:
sync foo
{
    foo.update();
}

// Correct:
foo.update();

Shared

shared is a type attribute. A shared type will be checked by the compiler on every usage of it to make sure it's used in a synchronized or thread-safe context.

Immutable types cannot be shared because they're already thread-safe by nature.

You cannot change a shared type directly. You must borrow it using the := operator.

var int:shared foo = 100;

fn cannotChangeFoo()
{
    foo++; // Error: foo is shared and must be in a synchronized or thread-safe context.
}

fn canChangeFoo()
{
    sync
    {
        var int borrowedFoo := foo; // Borrow ownership
        borrowedFoo++;
        foo = borrowedFoo; // Return ownership
    }
}