channel

CSP通信模型

Communicating Sequential Processes

关于CSP的理论,它的精确定义其实比较复杂,不过它的核心理念用一句话就可以概括:不要共享内存来通信;而是要用通信来共享内存(Don’t communicate by sharing memory; share memory by communicating)。

往一个关闭的channal里面接收数据能够接收到吗

package main

import "fmt"

func main() {
	ch := make(chan int, 1)
	ch <- 1

	close(ch)
	fmt.Println(<-ch)
	fmt.Println(<-ch)
	ch <- 1
}

可以,但是从channal里面写就会panic

type hchan struct {
  qcount   uint            // 当前队列中剩余元素个数,即len
  dataqsiz uint            // 环形队列长度,即可以存放的元素个数,cap
  buf      unsafe.Pointer  // 环形队列指针:队列缓存,头指针,环形数组实现
  elemsize uint16          // 每个元素的大小
  closed   uint32          // 关闭标志位
  elemtype *_type          // 元素类型
  sendx    uint            // 队列下标,指示元素写入时存放到队列中的位置
  recvx    uint            // 队列下标,指示元素从队列的该位置读出
  recvq    waitq           // 等待读消息的goroutine队列
  sendq    waitq           // 等待写消息的goroutine队列

  // lock protects all fields in hchan, as well as several
  // fields in sudogs blocked on this channel.
  //
  // Do not change another G's status while holding this lock
  // (in particular, do not ready a G), as this can deadlock
  // with stack shrinking.
  lock mutex              // 该锁保护hchan所有字段
}
// sending/receiving等待队列的链表实现
type waitq struct {
  first *sudog
  last  *sudog
}

hchan环形队列
hchan内部实现了一个环形队列作为缓冲区,队列的长度是创建channel时指定的。下图展示了一个可缓存6个元素的channel的示意图:

  • dataqsiz指示队列长度为6,即可缓存6个元素
  • buf指向队列的内存,队列中还剩余两个元素
  • qcount表示队列中还有两个元素
  • sendx指示后续写入的数据存储的位置,取值[0,6)
  • recvx指示从该位置读取数据,取值[0,6)

问题

1、能使用无缓存的channal做mutex吗

虽然没有缓存,但是可以有一个放入,多个放出,放出可以抽象成争抢锁

1、设置一个goroutine,专门来放入,因为没有拿就阻塞了,如果有人拿就退出

2、有人拿了,没有被阻塞,说明拿到锁了,开始执行任务,然后执行完的时候重新启动一个goroutine来放入锁,等待下一个拿到锁的人。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!