Skip to main content

Synchronization blocks

Sometimes, it's necessary to protect certain sections of your code from concurrent access. To address this need, Argon provides a construct called sync. Internally, this construct utilizes the concept of a monitor to automatically manage concurrent code sections.

Before diving into the usage of the sync construct, let's briefly explain what a monitor is:

A monitor is a synchronization construct that provides a way to protect shared resources or data in a multithreaded or concurrent program.

It ensures that only one thread can access the protected code or data at a time, preventing race conditions and maintaining data integrity by offering a high-level and structured approach to synchronization, simplifying the task of coordinating access to critical sections of code.

How use sync block

A synchronization block is composed of the sync keyword followed by a variable reference:

var myvar = 12

sync myvar {

}

In this example, we see how myvar is used as a synchronization point for the code block inside sync.

NB: If the value of the myvar variable were to change, subsequent sync calls made by other fibers might not synchronize correctly.

Now let's look at a more complex example:

import "io"

struct Counter {
pub var count

pub func inc(self) {
sync self {
self.count ++
}
}
}

counter := Counter@(0)

async func incrementer(max) {
for var i = 0; i < max; i++ {
counter.inc()
}
}

i1 := increment(1000)
i2 := increment(200)

await i1
await i2

counter.count |> io.print

This example demonstrates how to use synchronization to avoid concurrency issues when multiple threads or processes attempt to access and modify the same shared resource, in this case, the count variable within the Counter instance.