How to avoid deadlock in this golang program?

Here is my program which is producing deadlock, how do I avoid it and what is the recommended pattern to handle this kind of situation.

The problem is after timeout how do I detect that there is no reader on my channel ?

var wg sync.WaitGroup

func main() {	
	wg.Add(1)
	c := make(chan int)
	go readFromChannel(c, time.After(time.Duration(2)*time.Second))
	time.Sleep(time.Duration(5) * time.Second)
	c <- 10
	wg.Wait()
}

func readFromChannel(c chan int, ti <-chan time.Time) {
	select {
	case x := <-c:
		fmt.Println("Read", x)
	case <-ti:
		fmt.Println("TIMED OUT")
	}
	wg.Done()
}
var wg sync.WaitGroup

func main() {	
wg.Add(1)
c := make(chan int)
go readFromChannel(c, time.After(time.Duration(2)*time.Second))
c <- 10
time.Sleep(time.Duration(5) * time.Second)

wg.Wait()
}

func readFromChannel(c chan int, ti <-chan time.Time) {
select {
case x := <-c:
	fmt.Println("Read", x)
case <-ti:
	fmt.Println("TIMED OUT")
}
wg.Done()
}

Hi, I want to handle timeout, if I send on the channel before timeout than I will not have any timeout…

Hey @Praveen_Sharma. This will fix your deadlock.
Let me know if you have any questions!

Edit: The deadlock was occurring in your example because the main thread was stuck trying to write to c, when there was no one available to read from it. So by placing the write to c in a different goroutine, main is no longer blocked and can continue execution.

package main

import (
	"fmt"
	"sync"
	"time"
)

// Create a new sync.WaitGroup variable wg.
var wg sync.WaitGroup

func main() {
	// Add 1 to wg's counter.
	wg.Add(1)

	// Create a new channel of integers, c.
	c := make(chan int)

	// Start readFromChannel in a new goroutine and set
	// it's timeout to 1 second.
	go readFromChannel(c, time.After(time.Second))

    // Sleep for 2 seconds.
    time.Sleep(2 * time.Second)

	// Spawn another goroutine and send a value along channel c.
	go func() {
		c <- 10
	}()

	// Block until wg's counter is zero.
	wg.Wait()
}

// readFromChannel reads a value from a channel c, or prints out
// a message if a timeout occurs first.
func readFromChannel(c chan int, ti <-chan time.Time) {
	// Decrement wg's counter no matter how this function exits.
	defer wg.Done()

	// Try to read from channel c, but if the timeout occurs
	// before a value is read, continue with the timeout case.
	select {
	case x := <-c:
		fmt.Println("Read", x)
	case <-ti:
		fmt.Println("TIMED OUT")
	}
}
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.