Communication between two threads in Julia without blocking

Hi!
I am building a system that consist of multiple threads doing different work. For the purpose of this post, I am simplifying the code.

My system:

using ThreadPools

function work()
    (timer) -> begin
        stop = isready(running) && fetch(running) isa Stop
        if stop
            close(timer)
        else
            println("Hello!")
            schedule()
        end
    end
end

function schedule()
    Timer(work(), 2)
end

function manager()
    # Schedule first work()
    schedule()

    # Run till a signal to stop is received
    stop = isready(running) && fetch(running) isa Stop
    while ! stop
        if isready(sig)
            take!(sig)
            println("Received signal!!!")
        end

        stop = isready(running) && fetch(running) isa Stop
    end
end

function send_signal()
    sleep(8)
    put!(sig, true)
end

struct Stop end
running = Channel{Stop}(1)

sig = Channel{Bool}(1)

w1 = @tspawnat 2 manager()
errormonitor(w1)

w2 = @tspawnat 3 send_signal()
errormonitor(w2)

sleep(20)
put!(running, Stop())

So we have one thread (w2) that only put an element in the Channel sig after 8 seconds. Then we have another thread: w1, which has two main jobs. First, it has to periodically call work(). In the example, this happen every other second. The other job it has to do is to check if a signal has come on the Channel sig.

The system is supposed to run as long as I want it do. In the example, it will run in 20s, before a Stop signal is sent which will stop w1 and the timer.

The problem is that in manager() the process of waiting for a signal in sig is blocking the execution of work(). How can I run this simultaneously, without introducing another thread?

I could imagine to solve this with a shared variable guarded by a ReentrantLock using trylock
Will try if necessary…

Hmmm… I don’t understand how that will work…

Hi,

I’m using my phone so can’t play with the above code but what your describing is a pattern often applied in Actors and there happens to be a Julia implementation (that I’ve not used yet) that may prove useful

Regards,

I’m far from being an expert on this, but when a task has to wait for one of several conditions, I think it is easier to have only one Channel that stores all events, rather than having one Channel per event type.

This is a significant rewrite, only loosely based on your original example, but I believe it does what you want (for your MWE; perhaps not for your real application)

@enum Event WORK SIGNAL STOP
events = Channel{Event}(32)

timer = Timer(2, interval=2) do _
    put!(events, WORK)
end

w1 = Threads.@spawn begin
    sleep(8)
    put!(events, SIGNAL)
end

w2 = Threads.@spawn begin
    while true
        evt = take!(events)
        if evt == WORK
            println("Hello!")
        elseif evt == SIGNAL
            println("Received signal!")
        elseif evt == STOP
            println("Terminating")
            close(timer)
            return
        else
            println("Unknown event $evt")
        end
    end
end


sleep(20)
put!(events, STOP)

wait(w1)
wait(w2)