Simple communication between tasks

I’d like to have two simple tasks, that would symmetrically send values to each other.

function task1(other_task)
    res1 = send_to_other_task(other_task, 10)   # switch to task2 and blocks until it sends a value
    @show res1
    res2 = send_to_other_task(other_task, 15)
    @show res2

function task2(other_task, starting_value)
    @show starting_value
    result1 = send_to_other_task(other_task, 100)
    @show result1

julia> launch_communicating_tasks(task1, task2)
starting_value = 10
res1 = 100
result1 = 15
res2 = :end_of_task   # or somesuch flag value

How should I implement that? I tried yield, yieldto (both of which don’t seem to handle other-task exceptions natively, so it’s pretty rough going?), having two channels (but channels can switch on IO, which is definitely not what I’m going for, and they don’t really block the way I want?) Having a single one-value channel, and using a closed-over ref to pass values the other way around…

But well, the code is never behaving as I’d expect, and I get a hung REPL all the time… Can anyone give some high-level pointers? I’m sure I can figure out the details, but the docs are pretty sparse.

1 Like

I’ve made progress using yieldto, with a try block in the subtask that sends the exception + backtrace back to the main task. Looks workable…

Channel constructors take buffer size as an argument. Buffered channels should block like you want.

julia> c = Channel(1) do c
       for i in 1:10
       println("About to put $i")
       put!(c, i)
About to put 1
About to put 2
Channel{Any}(1) (2 items available)

Channels run until they can’t put the next argument (I’m guessing, for speed reasons?). put! doesn’t switch to the next task unless it can’t put its argument, which defeats the purpose. I believe that I can have a second put!(c, :dummy_put) to force blocking, but I couldn’t make it to work. Maybe my logic was wrong…