Waiting for Conditions
We have just learned how threads can interact with mutable data. When doing this, it is common that one thread would need to wait for a certain condition, e.g., for data provided by some other thread to be available. In many cases, channels provide a simple and powerful mechanism for this. However, for more complex situations, channels are not sufficient.
Concurrently observing mutable data
As an example, let us use a small application that counts numbers divisible
by 7 for three seconds using a mutable field:
It would be nice if this example could show the progress that has occurred. For this, we want to use a separate thread that waits for the counter to make a significant progress, in our case to have doubled.
mutate.wait
To do this, we can use feature mutate.wait in an exclusive code
section in a separate thread as follows: mutate.wait receives
a Unary bool argument that implements a condition we are waiting
for. Here, we want to wait for cnt to exceed
a limit, which is just cnt < limit. Additionally,
we want to exit once the main thread is done. We use a
mutable bool variable finish for this such that the
whole condition becomes cnt > limit || finish.
Here is the previous example with this progress reporting added. Note that
the operator *^ in Fuzion performs a saturating multiplication,
i.e., instead of causing a fault in case of an overflow, the result will
be i32.max, which gives us an easy means to handle overflows
here.
mutate.exclusive_when
Often, the first thing that needs to be done in an exclusive section is
to wait for some condition. Therefore, mutate
defines a feature exclusive_when that performs both, waiting for
a condition and running code exclusively.
The previous example can be simplified using exclusive_when using
two lambda arguments, one for the condition to wait for and a second one for
the code to execute once that condition holds:
Performance of Waiting for Conditions
Putting threads asleep to wait for a condition and waking them up to check if
that condition is met may easily create many superfluous thread switches. To
avoid this, Fuzion's mutate.wait keeps the waiting thread waiting
until the given condition is true. The condition will be checked by threads
leaving an exclusive section of the used mutate instance. If that
thread did not make any state changes that would result in the condition
becoming true, there will be no wake-up at all.