Thread-safe implementation for simple counter/mean

I have a callable which performs an iterative calculation, which is otherwise thread-safe. I would like to keep a statistic of the mean number of iterations that it used, and is thread-safe.

Stylized code follows:

mutable struct OnlineMean
    count::Int
    mean::Float64
    OnlineMean() = new(0, 0.0)
end

function update!(om::OnlineMean, x)
    om.count += 1
    om.mean += (x - om.mean) / om.count
    nothing
end

struct MyCallable
    … # other fields
    mean_iterations::OnlineMean
end

# this function called from various tasks
function (mc::MyCallable)(z)
    y, iterations = do_the_work_and_count(mc, z) # assume this is thread-safe
    update!(mc.mean_iterations, iterations) # QUESTION: make this thread-safe
    y
end

Is this as simple as putting a SpinLock in OnlineMean and using it in update!? Or should I somehow (how?) use Channels to pass in updates, or atomic operations…

Any of the above?

Spinlock is simple, and since the critical section is small, probably not too much at risk for starvation.

Channel has a lock internally, so it’s the same but with more memory overhead (and more complicated to control, since you need the one writer task that you need to maintain).

Atomics are probably optimal in terms of overhead, but they’ll be a bit tricky here since you need to update two things that can’t be written atomically at the same time due to both being 8 bytes large. Consider getting some inspiration from Sequence counters and sequential locks — The Linux Kernel documentation , the technique there can probably be adapted to your usecase, depending on how frequent you read/write data.

I’d use a ReentrantLock here by wrapping OnlineMean in Lockable. It’s probably good enough. Spinlocks are tricky to use and I doubt they provide much benefit over a ReentrantLock, but they do cause issues if you change the code so it can yield while the lock is taken.

I can’t think of a way to do this atomically, unless you instead store the sum and the count instead of the count and the mean.