github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/test/chan/doubleselect.go (about)

     1  // run
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // Test the situation in which two cases of a select can
     8  // both end up running. See http://codereview.appspot.com/180068.
     9  
    10  package main
    11  
    12  import (
    13  	"flag"
    14  	"runtime"
    15  )
    16  
    17  var iterations *int = flag.Int("n", 100000, "number of iterations")
    18  
    19  // sender sends a counter to one of four different channels. If two
    20  // cases both end up running in the same iteration, the same value will be sent
    21  // to two different channels.
    22  func sender(n int, c1, c2, c3, c4 chan<- int) {
    23  	defer close(c1)
    24  	defer close(c2)
    25  	defer close(c3)
    26  	defer close(c4)
    27  
    28  	for i := 0; i < n; i++ {
    29  		select {
    30  		case c1 <- i:
    31  		case c2 <- i:
    32  		case c3 <- i:
    33  		case c4 <- i:
    34  		}
    35  	}
    36  }
    37  
    38  // mux receives the values from sender and forwards them onto another channel.
    39  // It would be simpler to just have sender's four cases all be the same
    40  // channel, but this doesn't actually trigger the bug.
    41  func mux(out chan<- int, in <-chan int, done chan<- bool) {
    42  	for v := range in {
    43  		out <- v
    44  	}
    45  	done <- true
    46  }
    47  
    48  // recver gets a steam of values from the four mux's and checks for duplicates.
    49  func recver(in <-chan int) {
    50  	seen := make(map[int]bool)
    51  
    52  	for v := range in {
    53  		if _, ok := seen[v]; ok {
    54  			println("got duplicate value: ", v)
    55  			panic("fail")
    56  		}
    57  		seen[v] = true
    58  	}
    59  }
    60  
    61  func main() {
    62  	runtime.GOMAXPROCS(2)
    63  
    64  	flag.Parse()
    65  	c1 := make(chan int)
    66  	c2 := make(chan int)
    67  	c3 := make(chan int)
    68  	c4 := make(chan int)
    69  	done := make(chan bool)
    70  	cmux := make(chan int)
    71  	go sender(*iterations, c1, c2, c3, c4)
    72  	go mux(cmux, c1, done)
    73  	go mux(cmux, c2, done)
    74  	go mux(cmux, c3, done)
    75  	go mux(cmux, c4, done)
    76  	go func() {
    77  		<-done
    78  		<-done
    79  		<-done
    80  		<-done
    81  		close(cmux)
    82  	}()
    83  	// We keep the recver because it might catch more bugs in the future.
    84  	// However, the result of the bug linked to at the top is that we'll
    85  	// end up panicking with: "throw: bad g->status in ready".
    86  	recver(cmux)
    87  }