go chan 源码

  • 2022-07-15
  • 浏览 (896)

golang chan 代码

文件路径:/test/ken/chan.go

// 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 communication operations including select.

package main

import "os"
import "runtime"
import "sync"

var randx int

func nrand(n int) int {
	randx += 10007
	if randx >= 1000000 {
		randx -= 1000000
	}
	return randx % n
}

type Chan struct {
	sc, rc chan int // send and recv chan
	sv, rv int      // send and recv seq
}

var (
	nproc      int
	nprocLock  sync.Mutex
	cval       int
	end        int = 10000
	totr, tots int
	totLock    sync.Mutex
	nc         *Chan
)

func init() {
	nc = new(Chan)
}

func changeNproc(adjust int) int {
	nprocLock.Lock()
	nproc += adjust
	ret := nproc
	nprocLock.Unlock()
	return ret
}

func mkchan(c, n int) []*Chan {
	ca := make([]*Chan, n)
	for i := 0; i < n; i++ {
		cval = cval + 100
		ch := new(Chan)
		ch.sc = make(chan int, c)
		ch.rc = ch.sc
		ch.sv = cval
		ch.rv = cval
		ca[i] = ch
	}
	return ca
}

func expect(v, v0 int) (newv int) {
	if v == v0 {
		if v%100 == 75 {
			return end
		}
		return v + 1
	}
	print("got ", v, " expected ", v0+1, "\n")
	panic("fail")
}

func (c *Chan) send() bool {
	//	print("send ", c.sv, "\n");
	totLock.Lock()
	tots++
	totLock.Unlock()
	c.sv = expect(c.sv, c.sv)
	if c.sv == end {
		c.sc = nil
		return true
	}
	return false
}

func send(c *Chan) {
	for {
		for r := nrand(10); r >= 0; r-- {
			runtime.Gosched()
		}
		c.sc <- c.sv
		if c.send() {
			break
		}
	}
	changeNproc(-1)
}

func (c *Chan) recv(v int) bool {
	//	print("recv ", v, "\n");
	totLock.Lock()
	totr++
	totLock.Unlock()
	c.rv = expect(c.rv, v)
	if c.rv == end {
		c.rc = nil
		return true
	}
	return false
}

func recv(c *Chan) {
	var v int

	for {
		for r := nrand(10); r >= 0; r-- {
			runtime.Gosched()
		}
		v = <-c.rc
		if c.recv(v) {
			break
		}
	}
	changeNproc(-1)
}

func sel(r0, r1, r2, r3, s0, s1, s2, s3 *Chan) {
	var v int

	a := 0 // local chans running

	if r0.rc != nil {
		a++
	}
	if r1.rc != nil {
		a++
	}
	if r2.rc != nil {
		a++
	}
	if r3.rc != nil {
		a++
	}
	if s0.sc != nil {
		a++
	}
	if s1.sc != nil {
		a++
	}
	if s2.sc != nil {
		a++
	}
	if s3.sc != nil {
		a++
	}

	for {
		for r := nrand(5); r >= 0; r-- {
			runtime.Gosched()
		}

		select {
		case v = <-r0.rc:
			if r0.recv(v) {
				a--
			}
		case v = <-r1.rc:
			if r1.recv(v) {
				a--
			}
		case v = <-r2.rc:
			if r2.recv(v) {
				a--
			}
		case v = <-r3.rc:
			if r3.recv(v) {
				a--
			}
		case s0.sc <- s0.sv:
			if s0.send() {
				a--
			}
		case s1.sc <- s1.sv:
			if s1.send() {
				a--
			}
		case s2.sc <- s2.sv:
			if s2.send() {
				a--
			}
		case s3.sc <- s3.sv:
			if s3.send() {
				a--
			}
		}
		if a == 0 {
			break
		}
	}
	changeNproc(-1)
}

// direct send to direct recv
func test1(c *Chan) {
	changeNproc(2)
	go send(c)
	go recv(c)
}

// direct send to select recv
func test2(c int) {
	ca := mkchan(c, 4)

	changeNproc(4)
	go send(ca[0])
	go send(ca[1])
	go send(ca[2])
	go send(ca[3])

	changeNproc(1)
	go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
}

// select send to direct recv
func test3(c int) {
	ca := mkchan(c, 4)

	changeNproc(4)
	go recv(ca[0])
	go recv(ca[1])
	go recv(ca[2])
	go recv(ca[3])

	changeNproc(1)
	go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
}

// select send to select recv
func test4(c int) {
	ca := mkchan(c, 4)

	changeNproc(2)
	go sel(nc, nc, nc, nc, ca[0], ca[1], ca[2], ca[3])
	go sel(ca[0], ca[1], ca[2], ca[3], nc, nc, nc, nc)
}

func test5(c int) {
	ca := mkchan(c, 8)

	changeNproc(2)
	go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
	go sel(ca[0], ca[1], ca[2], ca[3], ca[4], ca[5], ca[6], ca[7])
}

func test6(c int) {
	ca := mkchan(c, 12)

	changeNproc(4)
	go send(ca[4])
	go send(ca[5])
	go send(ca[6])
	go send(ca[7])

	changeNproc(4)
	go recv(ca[8])
	go recv(ca[9])
	go recv(ca[10])
	go recv(ca[11])

	changeNproc(2)
	go sel(ca[4], ca[5], ca[6], ca[7], ca[0], ca[1], ca[2], ca[3])
	go sel(ca[0], ca[1], ca[2], ca[3], ca[8], ca[9], ca[10], ca[11])
}

// wait for outstanding tests to finish
func wait() {
	runtime.Gosched()
	for changeNproc(0) != 0 {
		runtime.Gosched()
	}
}

// run all tests with specified buffer size
func tests(c int) {
	ca := mkchan(c, 4)
	test1(ca[0])
	test1(ca[1])
	test1(ca[2])
	test1(ca[3])
	wait()

	test2(c)
	wait()

	test3(c)
	wait()

	test4(c)
	wait()

	test5(c)
	wait()

	test6(c)
	wait()
}

// run all test with 4 buffser sizes
func main() {

	tests(0)
	tests(1)
	tests(10)
	tests(100)

	t := 4 * // buffer sizes
		(4*4 + // tests 1,2,3,4 channels
			8 + // test 5 channels
			12) * // test 6 channels
		76 // sends/recvs on a channel

	if tots != t || totr != t {
		print("tots=", tots, " totr=", totr, " sb=", t, "\n")
		os.Exit(1)
	}
	os.Exit(0)
}

相关信息

go 源码目录

相关文章

go array 源码

go chan1 源码

go complit 源码

go convert 源码

go cplx0 源码

go cplx1 源码

go cplx2 源码

go cplx3 源码

go cplx4 源码

go cplx5 源码

0  赞