Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

if you run many goroutine some goroutine will be a deadlock #77

Closed
goofy-z opened this issue Dec 26, 2019 · 1 comment
Closed

if you run many goroutine some goroutine will be a deadlock #77

goofy-z opened this issue Dec 26, 2019 · 1 comment

Comments

@goofy-z
Copy link

goofy-z commented Dec 26, 2019

i have study golang for only 3 weeks i can not solve this problem

  1. if someone can help me to find out the reason why my program will block;
  2. i do many goroutine it has some wrong result ,some ip can ping right but pinger.PacketsRecv = 0
    image

i tried to find the reason, and i got some message

var wg sync.WaitGroup
recv := make(chan *packet, 5)
defer close(recv)
wg.Add(1)
go p.recvICMP(conn, recv, &wg)
err := p.sendICMP(conn)
if err != nil {
	fmt.Println(err.Error())
}
    timeout := time.NewTicker(p.Timeout)
defer timeout.Stop()
interval := time.NewTicker(p.Interval)
defer interval.Stop()

for {
	select {
	case <-p.done:
		wg.Wait()
		return
	case <-timeout.C:
		close(p.done)
		wg.Wait()
		return
	case <-interval.C:
		if p.Count > 0 && p.PacketsSent >= p.Count {
			continue
		}
		err = p.sendICMP(conn)
		if err != nil {
			fmt.Println("FATAL: ", err.Error())
		}
	case r := <-recv:
		err := p.processPacket(r)
		if err != nil {
			fmt.Println("FATAL: ", err.Error())
		}
	}
	if p.Count > 0 && p.PacketsRecv >= p.Count {
		close(p.done)
		wg.Wait()
		return
	}
}

i need to ping almost 16000 server ,if i use more goroutine to do this , block happen frequently
i debug my code , i found the reason
in ping.go 406

`

defer wg.Done()
for {
select {
case <-p.done:
fmt.Println("ok")
return
default:
bytes := make([]byte, 512)
conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100))
var n, ttl int
var err error
if p.ipv4 {
var cm *ipv4.ControlMessage
n, cm, _, err = conn.IPv4PacketConn().ReadFrom(bytes)
if cm != nil {
ttl = cm.TTL
}
} else {
var cm *ipv6.ControlMessage
n, cm, _, err = conn.IPv6PacketConn().ReadFrom(bytes)
if cm != nil {
ttl = cm.HopLimit
}
}
if err != nil {
if neterr, ok := err.(*net.OpError); ok {
if neterr.Timeout() {
// Read timeout
continue
} else {
close(p.done)
return
}
}
}
fmt.Println(len(recv))
recv <- &packet{bytes: bytes, nbytes: n, ttl: ttl}
}
}

`

the wg.Wait() is blocked by p.recvICMP(conn, recv, &wg)
and in the func recvICMP i foud in the for cycle
recv <- &packet{bytes: bytes, nbytes: n, ttl: ttl}
it will block by send a msg to the channel recv
but the chan recv := make(chan *packet, 5) only 5 size
if i do more goroutine i found the size 5 is not enough, so it will be blocked because the full channel ,
ok in some coincidence time the main goroutine dose not do the comsume func
case r := <-recv,
it is do close(p.done) then do wg.Wait() block to wait recvICMP
but in recvICMP
case <-p.done: fmt.Println("ok") return
this code will not effective because the block send msg to channel recv,so will not do
defer wg.Done()
then they all block like a deadlock
i sorry to my poor english
i don't konw i say my question clear
now i just do this to solve recv := make(chan *packet, 100)
by the way do many goroutine it has some wrong result ,some ip can ping right but pinger.PacketsRecv = 0

ivaivalous added a commit to tsarstva/go-ping that referenced this issue May 22, 2020
@CHTJonas
Copy link
Member

CHTJonas commented Feb 8, 2021

I believe this is the same issues at #78 and has been fixed by #85 in 70ede2a.

@CHTJonas CHTJonas closed this as completed Feb 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants