- つまり、チャネルはポインターを使用して受信キューと送信キューを維持します。このキューには、同時実行セキュリティ、データ型、要素の数、要素のサイズ、およびチャネルのステータスを確保するためのミューテックス ロックが含まれています。
- 次に、読み取りと書き込みの操作を行い、最初にキューが取り出せるかどうかを確認し、次にバッファを確認し、最後に受信/送信キューに入れます。
- 閉じるとは、すべてのゴルーチンを起動してフラグを 1 に設定することです。これはゴルーチンが閉じられていることを意味し、将来誰かがそれらを訪問した場合、それらは nil になります。
構造ソースコード
type hchan struct {
qcount uint // 当前队列中元素的数量
dataqsiz uint // 缓冲区大小,即可以缓存的元素数量
buf unsafe.Pointer // 指向队列的缓冲区
elemsize uint16 // 每个元素的大小
closed uint32 // channel 是否已关闭的标志
elemtype *_type // channel 中元素的类型
sendx uint // 下一次发送元素的位置
recvx uint // 下一次接收元素的位置
recvq waitq // 等待接收的 goroutine 队列
sendq waitq // 等待发送的 goroutine 队列
lock mutex // 用于保护 channel 的互斥锁
}
データを送る
goroutine がチャネルにデータを送信したい場合、 chansend
関数を実行します。
- この関数はまずチャネルをロックし、次に受信を待機しているゴルーチンがあるかどうかを判断します。
- がある場合は、そこにデータを直接送信します。そうでない場合、バッファがいっぱいでない場合は、データをバッファに入れて、キュー内の要素の数に 1 を加えます。
- キューがいっぱいの場合は、現在の goroutine を送信を待機している goroutine のキューに追加し、ブロックして、他の goroutine がデータを受信するのを待ちます。
データを受け入れる
goroutine がチャネルからデータを受信したい場合、 src/runtime/chan.go
の 関数を実行しますchanrecv
。
- この関数は、チャネルもロックし、送信を待っているゴルーチンがあるかどうかを判断し、存在する場合はそこから直接データを受信します。
- それ以外の場合、バッファー要素の数が 0 より大きい場合は、バッファーから要素が取得され、キュー内の要素の数が 1 つ減らされます。
- バッファが空の場合は、現在のgoroutine を受信を待機している goroutine のキューに追加し、ブロックして、他の goroutine がデータを送信するのを待ちます。
チャンネルを閉じる
goroutine がチャネルを閉じたい場合、 の src/runtime/chan.go
関数 を実行しますclosechan
。
- この関数はチャネルをロックし、
closed
チャネルが閉じられていることを示すフラグを 1 に設定します。 - 次に、送信と受信を待機しているゴルーチンのキューを走査し、それらをウェイクアップして、チャネルが閉じられていることを示す特別な値を返します。