Skip to content

A pair of communicating goroutines can starve other goroutines #1078

@nevkontakte

Description

@nevkontakte

The program below implements a typical timeout cancellation pattern for a pair communicating goroutines:

package main

import (
	"context"
	"time"
)

func main() {
	c := make(chan bool)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		time.Sleep(time.Second)
		cancel()
	}()
	go func() {
		for {
			select {
			case c <- true:
			case <-ctx.Done():
				return
			}
		}
	}()
	go func() {
		for {
			select {
			case <-c:
			case <-ctx.Done():
				return
			}
		}
	}()
	<-ctx.Done()
}

Under regular Go this program exits after 1 second as one may expect, however under GopherJS it runs forever: even though the two goroutines that are passing messages through the channel get blocked and unblocked on a regular basis, the sleeping goroutine never returns from the sleep.

I think what happens here is that the two communicating goroutines never return control to NodeJS's loop and the setTimeout's callback never has a chance to run. Although this probably isn't against the spec, this breaks a common usage pattern.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions