Atomic Counters in Julia

Our primary mechanism for managing state in Julia is communication over channels. We saw this for example with worker pools. There are a few other options for managing state though. Here we’ll look at using the Threads module for atomic counters accessed by multiple threads.

using Threads

function main()
    # We'll use an atomic integer type to represent our
    # (always-positive) counter.
    ops = Atomic{Int64}(0)

    # We'll start 50 threads that each increment the
    # counter exactly 1000 times.
    @threads for i in 1:50
        for c in 1:1000
            # To atomically increment the counter we use atomic_add!
            atomic_add!(ops, 1)
        end
    end

    # Here no threads are writing to 'ops', but it's safe to
    # atomically read a value even while other threads are
    # (atomically) updating it.
    println("ops: ", ops[])
end

main()

We expect to get exactly 50,000 operations. Had we used a non-atomic integer and incremented it with ops += 1, we’d likely get a different number, changing between runs, because the threads would interfere with each other. Moreover, we’d get data race issues.

$ julia atomic_counters.jl
ops: 50000

Next we’ll look at locks, another tool for managing state.