...
Run Format

Source file test/chan/doubleselect.go

Documentation: test/chan

  // run
  
  // Copyright 2009 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  // Test the situation in which two cases of a select can
  // both end up running. See http://codereview.appspot.com/180068.
  
  package main
  
  import (
  	"flag"
  	"runtime"
  )
  
  var iterations *int = flag.Int("n", 100000, "number of iterations")
  
  // sender sends a counter to one of four different channels. If two
  // cases both end up running in the same iteration, the same value will be sent
  // to two different channels.
  func sender(n int, c1, c2, c3, c4 chan<- int) {
  	defer close(c1)
  	defer close(c2)
  	defer close(c3)
  	defer close(c4)
  
  	for i := 0; i < n; i++ {
  		select {
  		case c1 <- i:
  		case c2 <- i:
  		case c3 <- i:
  		case c4 <- i:
  		}
  	}
  }
  
  // mux receives the values from sender and forwards them onto another channel.
  // It would be simpler to just have sender's four cases all be the same
  // channel, but this doesn't actually trigger the bug.
  func mux(out chan<- int, in <-chan int, done chan<- bool) {
  	for v := range in {
  		out <- v
  	}
  	done <- true
  }
  
  // recver gets a steam of values from the four mux's and checks for duplicates.
  func recver(in <-chan int) {
  	seen := make(map[int]bool)
  
  	for v := range in {
  		if _, ok := seen[v]; ok {
  			println("got duplicate value: ", v)
  			panic("fail")
  		}
  		seen[v] = true
  	}
  }
  
  func main() {
  	runtime.GOMAXPROCS(2)
  
  	flag.Parse()
  	c1 := make(chan int)
  	c2 := make(chan int)
  	c3 := make(chan int)
  	c4 := make(chan int)
  	done := make(chan bool)
  	cmux := make(chan int)
  	go sender(*iterations, c1, c2, c3, c4)
  	go mux(cmux, c1, done)
  	go mux(cmux, c2, done)
  	go mux(cmux, c3, done)
  	go mux(cmux, c4, done)
  	go func() {
  		<-done
  		<-done
  		<-done
  		<-done
  		close(cmux)
  	}()
  	// We keep the recver because it might catch more bugs in the future.
  	// However, the result of the bug linked to at the top is that we'll
  	// end up panicking with: "throw: bad g->status in ready".
  	recver(cmux)
  }
  

View as plain text