目录

channel

chansend, chanrec, closechan 的结果

/chan/image-20210820105731359.png

  • 黄色标记为返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    // chanrecv 有两个 bool 返回值 selected received
    // 例如:
    // select {
    // case v, ok =<- c:
    //    ...
    // }
    // selected : 表示 case 可以被 selected 
    // received : ok == true
    func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {}
    
  • block : blocking IO, 取决于是否有 default case

  • 1
    2
    3
    4
    5
    6
    
      func full(c *hchan) bool {
          if c.dataqsiz == 0 {
              return c.recvq.first == nil
          }
          return c.qcount == c.dataqsiz
      }
    
  • 1
    2
    3
    4
    5
    6
    
      func empty(c *hchan) bool {
          if c.dataqsiz == 0 {
              return atomic.Loadp(unsafe.Pointer(&c.sendq.first)) == nil
          }
          return atomic.Loaduint(&c.qcount) == 0
      }
    

源码

runtime/chan.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
type hchan struct {
	qcount   uint           // total data in the queue
	dataqsiz uint           // size of the circular queue
	buf      unsafe.Pointer // points to an array of dataqsiz elements
	elemsize uint16
	closed   uint32
	elemtype *_type // element type
	sendx    uint   // send index
	recvx    uint   // receive index
	recvq    waitq  // list of recv waiters
	sendq    waitq  // list of send waiters

	// 锁
	lock mutex
}

type waitq struct {
	first *sudog
	last  *sudog
}

语法糖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// compiler implements
//
//	select {
//	case c <- v:
//		... foo
//	default:
//		... bar
//	}
//
// as
//
//	if selectnbsend(c, v) {
//		... foo
//	} else {
//		... bar
//	}
//
func selectnbsend(c *hchan, elem unsafe.Pointer) (selected bool) {
	return chansend(c, elem, false, getcallerpc())
}

// compiler implements
//
//	select {
//	case v = <-c:
//		... foo
//	default:
//		... bar
//	}
//
// as
//
//	if selectnbrecv(&v, c) {
//		... foo
//	} else {
//		... bar
//	}
//
func selectnbrecv(elem unsafe.Pointer, c *hchan) (selected bool) {
	selected, _ = chanrecv(c, elem, false)
	return
}

// compiler implements
//
//	select {
//	case v, ok = <-c:
//		... foo
//	default:
//		... bar
//	}
//
// as
//
//	if c != nil && selectnbrecv2(&v, &ok, c) {
//		... foo
//	} else {
//		... bar
//	}
//
func selectnbrecv2(elem unsafe.Pointer, received *bool, c *hchan) (selected bool) {
	// TODO(khr): just return 2 values from this function, now that it is in Go.
	selected, *received = chanrecv(c, elem, false)
	return
}