123 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			V
		
	
	
import time
 | 
						|
import sync
 | 
						|
 | 
						|
struct St {
 | 
						|
	a int
 | 
						|
}
 | 
						|
 | 
						|
fn getint() int {
 | 
						|
	return 8
 | 
						|
}
 | 
						|
 | 
						|
fn f1(ch1 chan int, ch2 chan St, ch3 chan int, ch4 chan int, ch5 chan int, mut sem sync.Semaphore) {
 | 
						|
	mut a := 5
 | 
						|
	select {
 | 
						|
		a = <-ch3 {
 | 
						|
			a = 0
 | 
						|
		}
 | 
						|
		b := <-ch2 {
 | 
						|
			a = b.a
 | 
						|
		}
 | 
						|
		ch3 <- 5 {
 | 
						|
			a = 1
 | 
						|
		}
 | 
						|
		ch2 <- St{
 | 
						|
			a: 37
 | 
						|
		} {
 | 
						|
			a = 2
 | 
						|
		}
 | 
						|
		ch4 <- (6 + 7 * 9) {
 | 
						|
			a = 8
 | 
						|
		}
 | 
						|
		ch5 <- getint() {
 | 
						|
			a = 9
 | 
						|
		}
 | 
						|
		> 300 * time.millisecond {
 | 
						|
			a = 3
 | 
						|
		}
 | 
						|
	}
 | 
						|
	assert a == 3
 | 
						|
	sem.post()
 | 
						|
}
 | 
						|
 | 
						|
fn f2(ch1 chan St, ch2 chan int, mut sem sync.Semaphore) {
 | 
						|
	mut r := 23
 | 
						|
	for i in 0 .. 2 {
 | 
						|
		select {
 | 
						|
			b := <-ch1 {
 | 
						|
				r = b.a
 | 
						|
			}
 | 
						|
			ch2 <- r {
 | 
						|
				r = 17
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if i == 0 {
 | 
						|
			assert r == 17
 | 
						|
		} else {
 | 
						|
			assert r == 13
 | 
						|
		}
 | 
						|
	}
 | 
						|
	sem.post()
 | 
						|
}
 | 
						|
 | 
						|
fn test_select_blocks() {
 | 
						|
	ch1 := chan int{cap: 1}
 | 
						|
	ch2 := chan St{}
 | 
						|
	ch3 := chan int{}
 | 
						|
	ch4 := chan int{}
 | 
						|
	ch5 := chan int{}
 | 
						|
	mut sem := sync.new_semaphore()
 | 
						|
	mut r := false
 | 
						|
	t := select {
 | 
						|
		b := <-ch1 {
 | 
						|
			println(b)
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			// no channel ready
 | 
						|
			r = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
	assert r == true
 | 
						|
	assert t == true
 | 
						|
	go f2(ch2, ch3, mut sem)
 | 
						|
	n := <-ch3
 | 
						|
	assert n == 23
 | 
						|
	ch2 <- St{
 | 
						|
		a: 13
 | 
						|
	}
 | 
						|
	sem.wait()
 | 
						|
	stopwatch := time.new_stopwatch({})
 | 
						|
	go f1(ch1, ch2, ch3, ch4, ch5, mut sem)
 | 
						|
	sem.wait()
 | 
						|
	elapsed_ms := f64(stopwatch.elapsed()) / time.millisecond
 | 
						|
	// https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/high-resolution-timers
 | 
						|
	// > For example, for Windows running on an x86 processor, the default interval between 
 | 
						|
	// > system clock ticks is typically about 15 milliseconds, and the minimum interval 
 | 
						|
	// > between system clock ticks is about 1 millisecond.
 | 
						|
	assert elapsed_ms >= 280.0 // 300 - (15ms + 5ms just in case)
 | 
						|
 | 
						|
	ch1.close()
 | 
						|
	ch2.close()
 | 
						|
	mut h := 7
 | 
						|
	mut is_open := true
 | 
						|
	if select {
 | 
						|
		_ := <-ch2 {
 | 
						|
			h = 0
 | 
						|
		}
 | 
						|
		ch1 <- h {
 | 
						|
			h = 1
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			h = 2
 | 
						|
		}
 | 
						|
	} {
 | 
						|
		panic('channel is still open')
 | 
						|
	} else {
 | 
						|
		is_open = false
 | 
						|
	}
 | 
						|
	// no branch should have run
 | 
						|
	assert h == 7
 | 
						|
	// since all channels are closed `select` should return `false`
 | 
						|
	assert is_open == false
 | 
						|
}
 |