# LIFO Channels

**URL:** https://discourse.julialang.org/t/lifo-channels/31343
**Category:** General Usage
**Created:** [November 21, 2019, 9:18am UTC](https://discourse.julialang.org/t/lifo-channels/31343 "2019-11-21T09:18:24Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![jtackm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jtackm/32/4784_2.png) [@jtackm](https://discourse.julialang.org/u/jtackm)
#### Post date: [November 21, 2019, 9:18am UTC](https://discourse.julialang.org/t/lifo-channels/31343/1 "2019-11-21T09:18:24Z")

</div>

I have a parallel computation workflow that uses RemoteChannel-\>Channel to communicate results between master and worker nodes. Channels by default work like a queue (FIFO):

```julia
using Distributed

julia> shared_job_q = RemoteChannel(() -> Channel{Tuple}(1000))
julia> put!(shared_job_q, (1,0.1))
julia> put!(shared_job_q, (2,0.2))
julia> println(take!(shared_job_q))
(1, 0.1)
julia> println(take!(shared_job_q))
(2, 0.2)

```

However, my application would benefit from a stack (LIFO) behavior:

```julia
julia> putfirst!(shared_job_q, (1,0.1))
julia> putfirst!(shared_job_q, (2,0.2))
julia> println(take!(shared_job_q))
(2, 0.2)
julia> println(take!(shared_job_q))
(1, 0.1)

```

I can’t find a `putfirst!` method (or similar) in the official Channels API and making my own seems to require relying on internals (below is a quick prototype, based on Base/channels.jl and Distributed.jl), which I would really like to avoid. Would there be a better solution to this?

```julia
function check_channel_state(c::Channel)
    if !isopen(c)
        excp = c.excp
        excp !== nothing && throw(excp)
        throw(closed_exception())
    end
end

isbuffered(c::Channel) = c.sz_max==0 ? false : true

putfirst!(rr::RemoteChannel, args...) = (Distributed.call_on_owner(putfirst_ref, rr, args...); rr)
putfirst_ref(rid, args...) = (putfirst!(Distributed.lookup_ref(rid), args...); nothing)

function putfirst!(c::Channel{T}, v) where T
    check_channel_state(c)
    v = convert(T, v)
    return isbuffered(c) ? putfirst_buffered(c, v) : throw("putfirst! not implemented for unbuffered Channels")
end

function putfirst_buffered(c::Channel, v)
    lock(c)
    try
        while length(c.data) == c.sz_max
            check_channel_state(c)
            wait(c.cond_put)
        end
        pushfirst!(c.data, v)
        # notify all, since some of the waiters may be on a "fetch" call.
        notify(c.cond_take, nothing, true, false)
    finally
        unlock(c)
    end
    return v
end

```

---

<div class="post-metadata">

### Author: ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)
#### Post date: [June 22, 2020, 5:39pm UTC](https://discourse.julialang.org/t/lifo-channels/31343/2 "2020-06-22T17:39:13Z")

</div>

I’m facing the same issue. What was your solution in the end? Right now, I think this could be most elegantly achieved by making the underlying data structure of a `Channel` exchangeable. Ironically the current underlying data structure is a `Vector` – which for `push!()` and `pop!()` is LIFO – it’s just begin used FIFO because `take!()` calls `popfirst!()` instead of `pop!()`.

---

<div class="post-metadata">

### Author: ![jtackm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jtackm/32/4784_2.png) [@jtackm](https://discourse.julialang.org/u/jtackm)
#### Post date: [June 22, 2020, 6:01pm UTC](https://discourse.julialang.org/t/lifo-channels/31343/3 "2020-06-22T18:01:10Z")

</div>

No solution thus far, I still have a hacky implementation that relies on internals. Making the underlying data structure exchangable sounds like a reasonable plan to me, but perhaps people more knowledgeable than me could chime in on potential pitfalls?

---

<div class="post-metadata">

### Author: ![josuagrw](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/josuagrw/32/1015_2.png) [@josuagrw](https://discourse.julialang.org/u/josuagrw)
#### Post date: [June 22, 2020, 7:47pm UTC](https://discourse.julialang.org/t/lifo-channels/31343/4 "2020-06-22T19:47:03Z")

</div>

For reference, here’s my workaround

```nohighlight

# not ideal but Base doesn't leave us much choice
function lifo_take!(c::Channel)
    lock(c)
    try
        while isempty(c.data)
            check_channel_state(c)
            wait(c.cond_take)
        end
        v = pop!(c.data) # only line changed from Base.take!()
        notify(c.cond_put, nothing, false, false)
        return v
    finally
        unlock(c)
    end
end

struct LIFOChannel{T} <: AbstractChannel{T}
    channel::Channel{T}
end

LIFOChannel{T}(n::Int) where T = LIFOChannel(Channel{T}(n))

put!(lc::LIFOChannel, x) = put!(lc.channel, x)
take!(lc::LIFOChannel) = lifo_take!(lc.channel)

close(lc::LIFOChannel) = close(lc.channel)
isopen(lc::LIFOChannel) = isopen(lc.channel)

isready(lc::LIFOChannel) = isready(lc.channel)

lock(lc::LIFOChannel) = lock(lc.channel)
unlock(lc::LIFOChannel) = unlock(lc.channel)

```
