Threads.@Atomic error

Hi all, hoping someone here can help me answer a MultiThreaded problem I am having.

Here is my code:

n = 10000000;
numprimes = Threads.Atomic{Int}(0);

function is_prime(n)
        if n == 0 | n == 1
                return 0
        elseif n == 2
                return 1
        end
        root_n = isqrt(n)
        for i = 2:root_n
                if n%i == 0
                        return 0
                end
        end
        return 1
end



function main()
        Threads.@threads for i = 1:n
                if is_prime(i) == 1
                        global numprimes = atomic_add!(numprimes, 1)
                end
        end
end


main()

I am getting this error when trying to use a Threads.@Atomic variable to collect numprimes:

Error thrown in threaded loop on thread 0: MethodError(f=typeof(Base.:(+))(), args=(Base.Threads.Atomic{Int64}(value=0), 1), world=0x00000000000063ec)Thread ID:
1

And I can’t find something online to help me figure out how to solve this.

Would anyone have some insight on what I should change in my code?

Many thanks!

Remove the global numprimes = from inside the loop. atomic_add! returns the OLD value. so really you are changing numprimes to an Int the first time in the loop, then trying to do an atomic_add on an int rather than an atomic value.

However I think the actual error you are getting is that you have multiple threads trying to update a global variable (and change it’s type) and I don’t think Julia is happy about that.

global turned out not to be the problem, global needed to be there so it could be incremented and saved/ accessed properly later.

The problem was I was calling atomic_add! rather than Theads.atomic_add!, which gives the correct output.

I also changed my variable numprimes at the very top to equal 0, and I modified my for loop to:

function main()
        threadprimes = Threads.Atomic{Int}(0)
        Threads.@threads for i = 1:n
                if is_prime(i) == 1
                        global numprimes = Threads.atomic_add!(threadprimes, 1)
                end
        end
end

Thank you for your reply though! :slight_smile: I appreciate it.

function main()
    threadprimes = Threads.Atomic{Int}(0)
    Threads.@threads for i = 1:n
        if is_prime(i) == 1
            Threads.atomic_add!(threadprimes, 1)
        end
    end
    global numprimes = threadprimes[]
end

I think that would be better. The original function has a small race condition:

  1. Thread 1 increments threadprimes to 10.
  2. Thread 2 increments threadprimes to 11.
  3. Thread 2 sets numprimes to 11.
  4. Thread 1 sets numprimes to 10.

Which you would only see if it happen at the very end, but still. :slight_smile:

1 Like

Hi pixel27,

You are right - I just modified my code and it still gives the correct output on all threads. Thank you! This is the correct answer. I’m sorry if that is what you were trying to clarify originally in your previous response, as well. :slight_smile:

1 Like