Inspect value from channel

Issue

I have two read-only channels <-chan Event that utilized as generators.

type Event struct{
    time int
}

I can read their values as:

for {
    select {
    case <-chan1:
        // do something
    case <-chan2:
        //do something
    }

I use those channels for event-driven simulations so I have to choose the Event with the less time field.

Is it possible to inspect which value is going from each channel and only then choose from which one to read? Because the operation <-chan1 takes value from channel and it is impossible to push it back (read only channel).

Solution

You can implement your version of go channel structure. for example following implementation act like go channel without size limit and you can inspect its first element.

package buffchan

import (
    "container/list"
    "sync"
)

// BufferedChannel provides go channel like interface with unlimited storage
type BufferedChannel struct {
    m *sync.Mutex
    l *list.List
    c *sync.Cond
}

// New Creates new buffer channel
func New() *BufferedChannel {
    m := new(sync.Mutex)
    return &BufferedChannel{
        m: m,
        l: list.New(),
        c: sync.NewCond(m),
    }
}

// Append adds given data at end of channel
func (b *BufferedChannel) Append(v interface{}) {
    b.m.Lock()
    defer b.m.Unlock()

    b.l.PushBack(v)
    b.c.Signal()

}

// Remove removes first element of list synchronously
func (b *BufferedChannel) Remove() interface{} {
    b.m.Lock()
    defer b.m.Unlock()

    for b.l.Len() == 0 {
        b.c.Wait()
    }

    v := b.l.Front()
    b.l.Remove(v)

    return v.Value
}

// Inspect first element of list if exists
func (b *BufferedChannel) Inspect() interface{} {
    b.m.Lock()
    defer b.m.Unlock()

    for b.l.Len() == 0 {
        return nil
    }

    return b.l.Front().Value
}

// AsyncRemove removes first element of list asynchronously
func (b *BufferedChannel) AsyncNonBlocking() interface{} {
    b.m.Lock()
    defer b.m.Unlock()

    for b.l.Len() == 0 {
        return nil
    }

    v := b.l.Front()
    b.l.Remove(v)

    return v.Value
}

Answered By – Parham Alvani

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.