Trigger a channel inside the loop where the the channel is consumed

Issue

How to rigger a channel inside the loop where the same channel is consumed. Below is a sample code that does not work. How is this achievable?

https://go.dev/play/p/o5ZhNfw4IFu

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan struct{})
    ch2 := make(chan struct{})
    defer close(ch1)
    defer close(ch2)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
    defer cancel()

    go func() {
        time.Sleep(time.Second * 1)
        ch1 <- struct{}{}
    }()

loop:
    for {
        select {
        case <-ctx.Done():
            fmt.Println("timeout")
            break loop
        case <-ch1:
            fmt.Println("ch1")
            ch2 <- struct{}{} // This here does not work!
        case <-ch2:
            fmt.Println("ch2")
        }
    }

}

Solution

1. send data to ch2 inside goroutine

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan struct{})
    ch2 := make(chan struct{})
    defer close(ch1)
    defer close(ch2)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
    defer cancel()

    go func() {
        time.Sleep(time.Second * 1)
        ch1 <- struct{}{}
    }()

loop:
    for {
        select {
        case <-ctx.Done():
            fmt.Println("timeout")
            break loop
        case <-ch1:
            fmt.Println("ch1")
            go func() {
                ch2 <- struct{}{}
            }()
        case <-ch2:
            fmt.Println("ch2")
        }
    }

}

or

2. make ch2 buffered

package main

import (
    "context"
    "fmt"
    "time"
)

func main() {
    ch1 := make(chan struct{})
    ch2 := make(chan struct{}, 1)
    defer close(ch1)
    defer close(ch2)

    ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
    defer cancel()

    go func() {
        time.Sleep(time.Second * 1)
        ch1 <- struct{}{}
    }()

loop:
    for {
        select {
        case <-ctx.Done():
            fmt.Println("timeout")
            break loop
        case <-ch1:
            fmt.Println("ch1")
            ch2 <- struct{}{}
        case <-ch2:
            fmt.Println("ch2")
        }
    }

}

Answered By – Rahmat Fathoni

Answer Checked By – David Goodson (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.