Threads with Channels sometimes lead to weird code excecution

I think something like this works fairly well. The other tasks will continue until the test in the while loop is encountered. But it’s possible to insert some done[] && return inside the loop as well.


function func_busy(i, done)
    while !done[]
        r = rand()
        if r < 1e-10
            done[] = true
            @ccall printf("found one %.3le\n"::Cstring; r::Cdouble)::Cint
            Libc.flush_cstdio()
            return r
        end
    end
    return nothing
end


function threaded_f(f)

    c = Channel(1)
    done = Threads.Atomic{Bool}(false)
    tasks = [Threads.@spawn begin
                 local r = f(i, done)
                 isnothing(r) || put!(c, r)
             end for i in 1:(Threads.nthreads()-1)]

    println("taking")
    res = take!(c)::Float64
    println("result: ", res)
    println("waiting for all tasks")
    wait.(tasks)
    close(c)
    println("all done")
end

println(Threads.nthreads())
threaded_f(func_busy)

Note that it won’t work if nthreads() == 1.

1 Like