2021/12,江端さんの技術メモ

お題: subPerson1が終了したら subPerson2も巻き添えで強制的に終了させるには?
当初、一方が終了したら、他方も終了するように作りたかったのだけど、いいやり方が思いつかなかったので、subPerson1 → subPerson2 の順番で終わせるような実装にした。
まあ、subPerson1を送信専用、subPerson2を受信専用のgoroutineとすれば、まあ、いけるんじゃないかな、と
/*
	お題: subPerson1が終了したら subPerson2も巻き添えで強制的に終了させるには?
	当初、一方が終了したら、他方も終了するように作りたかったのだけど、分からなかったので、subPerson1 → subPerson2 の順番で終わせるような実装にした
*/

package main

import (
	"fmt"
	"sync"
	"time"
)

func subPerson1(i int, wg *sync.WaitGroup, ch chan struct{}) {
	defer wg.Done()
	time.Sleep(1 * time.Second)
	fmt.Println("		End of sub_person1(", i, ")")
	close(ch) // subPerson2に終了を通知する
}

func subPerson2(i int, wg *sync.WaitGroup, ch chan struct{}) {
	defer wg.Done()
	<-ch // subPerson1 のclose(ch)が発行されるまでロック (普通はselect待ちにする)
	fmt.Println("		End of sub_person2(", i, ")")
}

func person(i int, wg *sync.WaitGroup) {
	fmt.Println("	Start... person(", i, ")")
	defer wg.Done()

	subWG := sync.WaitGroup{}

	subWG.Add(2)
	ch := make(chan struct{})
	go subPerson1(i, &subWG, ch)
	go subPerson2(i, &subWG, ch)

	subWG.Wait()

	fmt.Println("	End... person(", i, ")")
}

func main() {
	fmt.Println("start... main()")
	wg := sync.WaitGroup{}
	for i := 0; i < 5; i++ {
		wg.Add(1) // goルーチンを実行する関数分だけAddする

		go person(i, &wg)
	}

	wg.Wait()
	fmt.Println("end of ... main()")
}
出力結果
ebata@DESKTOP-P6KREM0 MINGW64 ~/goga/0-2
$ go run main.go
start... main()
        Start... person( 4 )
        Start... person( 0 )
        Start... person( 1 )
        Start... person( 3 )
        Start... person( 2 )
                End of sub_person1( 3 )
                End of sub_person2( 3 )
        End... person( 3 )
                End of sub_person1( 0 )
                End of sub_person1( 4 )
                End of sub_person2( 4 )
        End... person( 4 )
                End of sub_person2( 0 )
        End... person( 0 )
                End of sub_person1( 1 )
                End of sub_person2( 1 )
        End... person( 1 )
                End of sub_person1( 2 )
                End of sub_person2( 2 )
        End... person( 2 )
end of ... main()

とまあこんな感じで、sub_person1 → sub_person2 → person という順番でgoroutineが終了していることが確認できました。

2021/12,江端さんの技術メモ

先程、情報開示請求先の、総務省の担当者の方から、『本日中に資料を送付して頂ける』旨の電話連絡を頂きました。

総務省の方からお電話頂き、調べ方について丁寧に御説明頂きました。まずは手順を忘れない内にメモを残しておきます。(政治資金収支報告書のオンライン提出を怠っている政治団体を全部開示する件 続報)

I received a phone call from the person in charge at the Ministry of Internal Affairs and Communications, to whom I made a request for information disclosure, stating that they would be able to send me the documents today.

そもそも、存在していなかった資料をわざわざ作って頂いているので、時間がかかるのは覚悟しているたのですが ――

I was prepared for it to take a long time, since they had to create a document that didn't exist in the first place, however...

それにしても、丁寧なフォローをして頂いて、恐縮してしまいます。

Nevertheless, I'm very grateful for their careful follow-up.

-----

親切が嬉しい反面、ちょっと心配になってきました。

While I'm glad for their kindness, I'm getting a little worried.

この対応の理由には、3つのケースが考えられると思うからです。

The reason for this response is that I think there are three possible cases.

(1)基本的に総務省の担当者の方が親切

(1) Basically, the person in charge at the Ministry of Internal Affairs and Communications is kind.

(2)情報開示請求をしてくるような民間人はやっかな奴が多い → その対応のノウハウがある

(2) Many private citizens who request disclosure of information are difficult, so they have the know-how to deal with them.

(3)こんなコラムを書いているような奴(江端)を怒らせると面倒

(3) A guy who writes a column like this (Ebata) can be a pain in the ass if they piss him off.

上記の(1)だといいけど、(3)だとちょっと悲しいなぁ、と思っています。

I hope it's (1) above, but if it's (3), I'm a little sad.

-----

あ、第4のケースもありそうです。

Oh, there may be the fourth case.

(4)「政治資金収支報告書のオンライン提出を怠っている政治団体」を、江端から思いっきりDisって欲しい

(4) They want Ebata to disrespect "political organizations that fail to submit their political fund balance reports online" with all his might.

うん、これありそうだな。

Yeah, that's a possibility.

『政府としては、政治団体に恥をかかせるのはマズいけど、民間人のライター(江端)がやってくれるなら、それに越したことはない』

"It's not good for the government to embarrass a political group, but if a civilian writer (Ebata) can do it, so much the better"

と。

これなら、政府と私が、Win-Winです。

This is a win-win situation for the government and me.

-----

まあ、こんな感じで、『アナログ かつ アナクロ な政治団体を見張っていくのは、私のようなシニアの義務だろう』てなことを思っています。

In this way, I think it is the duty of senior citizens like me to keep an eye on analog and analogous political organizations.

2021/12,江端さんの技術メモ

C/C++では、構造体を丸ごと送信するのに、文字列にキャストを被せて無理矢理送り込むということをやっていました。

Goの場合、チャネルに ch chan interface{}を使うと、何でも運んでくれるようなので、これで同じように「手を抜く」を考えていました。

で、色々試した結果、こういう風に使えるらしいので自分用のメモとして残しておきます

// 単一通信の構造体
type SingleCaster struct {
	//ch   chan int   // 単一通信路
	ch   chan interface{}
	lock sync.Mutex // 単一通信路のロック
}

でもって、

type locInfo struct {
	lon float64
	lat float64
}
でもって、
type PERSON struct {
    number      int     // 人間番号
    live        bool    // 存在フラグ 存在:true 消滅:false
    destination locInfo // 出発座標
    arrival     locInfo // 到着座標
    distance    float64 // 到着座標と出発座標の距離
    present     locInfo // 現在位置
}

を、こんな風に運びたい時、

sc_person.ch <- person.present

これで、元に戻ります。

case v_p := <-sc_person.ch:
			fmt.Println("catched from person send", v_p)
			//var ll locInfo
			ll := v_p.(locInfo)
			fmt.Println(ll.lon, ll.lat)

channelで構造体を送り込む方法

var ch1 chan interface{}

type PERSON struct {
	number      int     // 人間番号
	action      int     // 0:リクエスト 1:乗車 2:降車
}

func sub1(){
	 var person PERSON
	 person.number = 1
	 person.action= 2

	 ch1 <- person 
} 

func sub2(){

	 p := <-ch1

	 person := p.(PERSON)
	 fmt.Println(person) 
}

2021/11,江端さんの技術メモ

  • Go言語のコーディングしている最中に、バグを指摘してくる(お前はツンデレ彼女か)
  • 適当なメソッドを書き込むと、自動的にimport関数を付け加えてくるところ(お前はお袋か)
  • バグではないけど、不効率なコーディングをしていると、もっと良いやり方を提案してくる(お前は構いたがりのメンターか)

―― なんか、ちょっと怖い

 

 

2021/11,江端さんの技術メモ

https://teratail.com/questions/370090?nli=619ad631-d4fc-405f-a649-44670a040506#reply-502318

もの凄く助かりました。

nobonoboさんに心からの感謝を

C:\Users\ebata\goga\3-10

/*
いっせいブロードキャストをするのに一般的に使われているのはPubSubと呼ばれる方式です。
サブスクライブを複数あらかじめおこなっておき、パブリッシュでメッセージを送ると
複数のサブスクライブ先に同じメッセージを配信するというものです。
おそらくこの方式は発見済みで、想像するに複数のサブスクライブ先をループで巡って
複数回送信することでブロードキャスト相当を実現するのではなく、もっと真に
ブロードキャストしたいということが質問者さんの意図なのかなと。

そういうものを実現するのに「sync.Cond」という標準ライブラリ機能があります。
これの活用方法は実はちゃんとした実例が見つけにくいです。たいてい前者のやり方で済まして
しまっているのと、sync.Condの挙動は若干わかりづらいです。

すこし解説は端折りますが、以下のように記述することで実現できると思います。

ポイントは

タイミングだけをsync.CondのBroadcastで伝える
複数のタスクには共有メモリを通して渡したいメッセージを伝えます
送る方も受ける方も排他ロックを併用するのがCondの使い方でロック期間であれば
共有メモリをコンフリクトなくアクセスできます

この方法はPubSubにくらべ、共有メモリをすべてのgoroutineタスクに伝播したか
どうかを保証する仕組みがないです
つまり、この方法は「低頻度のイベントを大量のタスクに配信」するか、もしくは
「最新の値さえ受け取れればOK」という用途向けです。
*/

package main

import (
	"fmt"
	"log"
	"sync"
	"time"
)

type BroadCaster struct {
	cond *sync.Cond
	id   int64
	msg  string
}

func (bc *BroadCaster) Send(msg string) {
	bc.cond.L.Lock()
	defer bc.cond.L.Unlock()
	bc.id++
	bc.msg = msg
	bc.cond.Broadcast()
}

func (bc *BroadCaster) Recv(last int64) (int64, string) {
	bc.cond.L.Lock()
	defer bc.cond.L.Unlock()
	for bc.id == last {
		bc.cond.Wait()
	}
	return bc.id, bc.msg
}

var (
	broadcaster = &BroadCaster{
		cond: sync.NewCond(&sync.Mutex{}),
	}
)

func task(i int) {
	log.Println("task:", i, " start")
	defer log.Println("task:", i, " stop")
	last := int64(0)
	for {
		id, msg := broadcaster.Recv(last)
		last = id
		log.Println("task:", i, msg)
	}
}

func main() {
	for i := 0; i < 3; i++ {
		go task(i)
	}
	for i := 0; i < 3; i++ {
		time.Sleep(1 * time.Second)
		broadcaster.Send(fmt.Sprintf("hello, world: %d", i))
	}
	time.Sleep(1 * time.Second)
}

Keyword sync.Cond, sync.Broadcast,

参考文献: sync.Cond/コンディション変数についての解説

2021/11,江端さんの技術メモ

wg.Add():   wg.Add(n)でn個の並行処理が存在することを伝え

wg.Done(): wg.Done()で終了を伝える

wg.Wait():wg.Wait()で並行処理が終わるまで(wg.Done()で終了を伝えるまで)処理をやめない

2021/11,江端さんの技術メモ

=======================

https://github.com/SierraSoftworks/multicast

マルチキャストでは、チャンネルをリスナーのリンクリストとして実装しています。リスナーは、受信したメッセージを次のリスナーに自動的に転送してから、自分のCチャンネルで公開します。

このアプローチにより、チャネルに属するリスナーの配列を維持する必要がなくなり、実装が大幅に簡素化されます。

=======================

以下は、readme.mdに記載されているプログラムを、ちょっとだけ改造したもの(syncを加えた)

package main

import (
	"fmt"
	"sync"

	"github.com/SierraSoftworks/multicast"
)

func main() {
	c := multicast.New()
	wg := sync.WaitGroup{}

	wg.Add(2)

	go func() {
		l := c.Listen()
		wg.Done()
		defer wg.Done()
		for msg := range l.C {
			fmt.Printf("Listener 1: %s\n", msg)
		}
		fmt.Println("Listener 1 Closed")
	}()

	go func() {
		l := c.Listen()
		wg.Done()
		defer wg.Done()
		for msg := range l.C {
			fmt.Printf("Listener 2: %s\n", msg)
		}
		fmt.Println("Listener 2 Closed")
	}()

	wg.Wait()
	wg.Add(2)

	c.C <- "1 Hello World!"
	c.C <- "2 Hello World!"
	c.C <- "3 Hello World!"
	c.C <- "4 Hello World!"

	c.Close()

	wg.Wait()
}

 

ebata@DESKTOP-P6KREM0 MINGW64 ~/goga/3-7
$ go run main.go
Listener 1: 1 Hello World!
Listener 1: 2 Hello World!
Listener 2: 1 Hello World!
Listener 2: 2 Hello World!
Listener 2: 3 Hello World!
Listener 2: 4 Hello World!
Listener 2 Closed
Listener 1: 3 Hello World!
Listener 1: 4 Hello World!
Listener 1 Closed

久しぶりに、「世界に感謝を」という気持ちになりました。

https://github.com/SierraSoftworks/multicast/blob/main/channel.goの、コメントに日本語コメント(翻訳)を付けたもの

package multicast

import "sync"

// Channel represents a multicast channel container which provides
// a writable channel C and allows multiple listeners to be connected.
// Channelは、書き込み可能なチャンネルCを提供し、複数のリスナーの接続を可能にする
// マルチキャストチャンネルコンテナを表します。

type Channel struct {
	// C is a writable channel on which you can send messages which will
	// be delivered to all connected listeners.
	// Cは書き込み可能なチャンネルで、接続されているすべてのリスナーに配信される
        // メッセージを送ることができます。

	C chan<- interface{}

	c chan interface{}
	l *Listener
	m sync.Mutex
}

// New creates a new multicast channel container which can have listeners
// connected to it and messages sent via its C channel property.
// このコンテナにはリスナーが接続され、C channelプロパティでメッセージが送信されます。

func New() *Channel {
	c := make(chan interface{})

	return From(c)
}

// From creates a new multicast channel which exposes messages it receives
// on the provided channel to all connected listeners.
// Fromは、新しいマルチキャストチャネルを作成し、提供されたチャネルで受信した
// メッセージを、接続されているすべてのリスナーに公開します。

func From(c chan interface{}) *Channel {
	return &Channel{
		C: c,
		c: c,
	}
}

// Listen returns a new listener instance attached to this channel.
// Each listener will receive a single instance of each message sent
// to the channel.
// Listenは、このチャンネルに接続された新しいリスナーのインスタンスを返します。
//各リスナーは、チャンネルに送信された各メッセージのインスタンスを1つずつ受信します。

func (c *Channel) Listen() *Listener {
	c.m.Lock()
	defer c.m.Unlock()

	if c.l == nil {
		c.l = NewListener(c.c)
	} else {
		c.l = c.l.Chain()
	}

	return c.l
}

// Close is a convenience function for closing the top level channel.
// You may also close the channel directly by using `close(c.C)`.
// Closeは、トップレベルのチャンネルを閉じるための便利な関数です。
// close(c.C)`を使ってチャンネルを直接閉じることもできます。

func (c *Channel) Close() {
	c.m.Lock()
	defer c.m.Unlock()

	close(c.c)
}

 

https://github.com/SierraSoftworks/multicast/blob/main/listener.goの、コメントに日本語コメント(翻訳)を付けたもの

package multicast

// Listener represents a listener which will receive messages
// from a channel.
// リスナーは、チャンネルからのメッセージを受信するリスナーを表します。
type Listener struct {
	C <-chan interface{}
	f chan interface{}
}

// NewListener creates a new listener which will forward messages
// it receives on its f channel before exposing them on its C
// channel.
// NewListenerは、Cチャンネルで公開する前に、fチャンネルで受信したメッセージを
// 転送する新しいリスナーを作成します。

// You will very rarely need to use this method directly in your
// applications, prefer using From instead.
// アプリケーションでこのメソッドを直接使用することはほとんどないと思いますが、
// 代わりにFromを使用してください。

func NewListener(source <-chan interface{}) *Listener {
	out := make(chan interface{}, 0)
	l := &Listener{
		C: out,
	}

	go func() {
		for v := range source {
			if l.f != nil {
				l.f <- v
			}
			out <- v
		}

		if l.f != nil {
			close(l.f)
		}
		close(out)
	}()

	return l
}

// Chain is a shortcut which updates an existing listener to forward
// to a new listener and then returns the new listener.
// Chainは、既存のリスナーを更新して新しいリスナーに転送し、
// その新しいリスナーを返すショートカットです。

// You will generally not need to make use of this method in your
// applications.
// 一般的には、このメソッドを使用する必要はありません。

func (l *Listener) Chain() *Listener {
	f := make(chan interface{})
	l.f = f
	return NewListener(f)
}

 

package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/SierraSoftworks/multicast"
)

func bus_func(i int, wg *sync.WaitGroup, ch *multicast.Channel) {

	l := ch.Listen()
	wg.Done()
	defer wg.Done()

	/*
		// これだといいんだけど、多面待ちができない
		for msg := range l.C {
			fmt.Printf("Listener %d: %s\n", i, msg)
		}

	*/

	for {
		select {
		case v := <-l.C:
			if v == nil {
				return
			}
			fmt.Println(i, v)
		}
		//time.Sleep(1 * time.Second)
	}

	//fmt.Printf("Listener %d Closed\n", i)
}

func main() {
	c := multicast.New()
	wg := sync.WaitGroup{}

	/*
		wg.Add(2)
		go func() {
			l := c.Listen()
			wg.Done()
			defer wg.Done()
			for msg := range l.C {
				fmt.Printf("Listener 1: %s\n", msg)
			}
			fmt.Println("Listener 1 Closed")
		}()

		go func() {
			l := c.Listen()
			wg.Done()
			defer wg.Done()
			for msg := range l.C {
				fmt.Printf("Listener 2: %s\n", msg)
			}
			fmt.Println("Listener 2 Closed")
		}()
	*/

	for i := 0; i < 3; i++ {
		wg.Add(1)
		go bus_func(i, &wg, c)
	}

	wg.Wait()
	wg.Add(2)

	c.C <- "1 Hello World!"
	time.Sleep(time.Second)

	c.C <- "2 Hello World!"
	time.Sleep(time.Second)

	c.C <- "3 Hello World!"
	time.Sleep(time.Second)
	c.C <- "4 Hello World!"

	c.Close()

	wg.Wait()
}

 

package main

import (
	"fmt"
	"sync"
	"time"

	"github.com/SierraSoftworks/multicast"
)

func bus_func(i int, wg *sync.WaitGroup, ch *multicast.Channel) {

	l := ch.Listen()
	wg.Done()
	defer wg.Done()

	/*
		// これだといいんだけど、多面待ちができない
		for msg := range l.C {
			fmt.Printf("Listener %d: %s\n", i, msg)
		}

	*/

	tick := time.Tick(time.Millisecond * 10000)

	for {
		select {
		case v := <-l.C:
			if v == nil { // c.Close() で goroutineをクローズする
				return
			}
			fmt.Println(i, v)

		case t := <-tick:
			// ここに送信するものを入れる
			fmt.Println("tiched", t)
		}

		//time.Sleep(1 * time.Second)
	}

	//fmt.Printf("Listener %d Closed\n", i)
}


func main() {
	c := multicast.New()
	wg := sync.WaitGroup{}

	/*
		wg.Add(2)
		go func() {
			l := c.Listen()
			wg.Done()
			defer wg.Done()
			for msg := range l.C {
				fmt.Printf("Listener 1: %s\n", msg)
			}
			fmt.Println("Listener 1 Closed")
		}()

		go func() {
			l := c.Listen()
			wg.Done()
			defer wg.Done()
			for msg := range l.C {
				fmt.Printf("Listener 2: %s\n", msg)
			}
			fmt.Println("Listener 2 Closed")
		}()
	*/

	for i := 0; i < 5; i++ { // ここの"5"は  (Aに飛ぶ)
		wg.Add(1)
		go bus_func(i, &wg, c)
	}

	wg.Wait()

	wg.Add(5) // (Aから)ここの"5"と一致している必要がある(が理由が分からん)

	c.C <- "11111!"
	//time.Sleep(time.Second)

	c.C <- "22222!"
	//time.Sleep(time.Second)

	c.C <- "33333!"
	//time.Sleep(time.Second)

	c.C <- "44444!"
	//time.Sleep(3 * time.Second)

	c.Close() // これでスレッドを全部止める

	wg.Wait()
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2021/11,江端さんの技術メモ

package main

import (
"fmt"
"time"
)

var ch chan int // チャネルを運ぶためのグローバルチャネル

func bus_func(i int) {
ch = make(chan int) // スレッドの中でチャネルを作っても動かない

ch <- 10
fmt.Println("After", ch)

time.Sleep(3)
}

func main() {

go bus_func(1)

fmt.Println(<-ch)

}

スレッドの中で(というかサブルーチンの中で)チャネルは厳しいのかな?

package main

import (
	"fmt"
	"time"
)

var ch chan int // チャネルを運ぶためのグローバルチャネル

func bus_func(i int) {

	ch <- 10
	fmt.Println("After", ch)

	time.Sleep(3)
}

func main() {

	ch = make(chan int) // メインで作った場合は動く

	go bus_func(1)

	fmt.Println(<-ch)

}

チャネルを定数で確保しない方法ってないかなぁ。

スレッドで、オブジェクトを実体化して、そこで送受信させる。

package main

import (
	"fmt"
	"sync"
	"time"
)

type BUS struct {
	number int
}

func bus_func(i int, wg *sync.WaitGroup, ch1 chan int, ch2 chan int) {
	defer wg.Done()

	t := time.NewTicker(1 * time.Second) // 1秒おきに通知

	bus := BUS{}
	bus.number = i

	pointer_bus := &bus

	fmt.Println(pointer_bus)

	// 待受
	for {
		select {
		case v := <-ch1: // 受信
			if v == -1 { //終了コードの受信
				return // スレッドを自滅させる
			} else {
				fmt.Println(v)
			}
		case <-t.C: // 送信 (1秒まったら、むりやりこっちにくる)
			ch2 <- i + 100
		}
	}

}

//var c = make([]chan int, 3) // 間違い
// var c []chan int  これは実行時にエラーとなる

var c1 [3]chan int // チャネルをグローバル変数で置く方法の、現時点での正解
var c2 [3]chan int // チャネルをグローバル変数で置く方法の、現時点での正解

func main() {
	var wg sync.WaitGroup
	defer wg.Wait()

	//c := make(chan int)

	// バスエージェントの生成 3台
	for i := 0; i < 3; i++ {
		wg.Add(1)

		c1[i] = make(chan int)
		c2[i] = make(chan int)
		go bus_func(i, &wg, c1[i], c2[i])
	}

	// バスエージェントにメッセージを送る

	c1[0] <- 50
	c1[1] <- 30
	c1[2] <- 10

	c1[0] <- 50
	c1[1] <- 30
	c1[2] <- 10

	c1[0] <- 50
	c1[1] <- 30
	c1[2] <- 10

	fmt.Println(<-c2[0])
	fmt.Println(<-c2[1])
	fmt.Println(<-c2[2])

	c1[0] <- -1 // スレッド終了コードの送信
	c1[1] <- -1 // スレッド終了コードの送信
	c1[2] <- -1 // スレッド終了コードの送信

}

2021/11,未分類,江端さんの技術メモ

これまでC/C++言語で作ってきたスケーラブルなエージェントシミュレーションを、golangで作りかえようとしています。

これまでもメイン関数に縛られずに、スレッドを自由に動き回すシミュレータは作ってきたのですが、C/C++のスレッドは、いかんせんメモリサイズが大きく、万の単位のエージェントには耐えられないという問題があります。

そんな感じで、golangに乗り換えしているのですが、色々文法が面倒くさいです。

例えば、スレッドの中で作った構造体と通信を行う方法として、go func() で返り値(return)が欲しいと思っていたのだけど、考えてみれば、スレッド化したfunc()は、それが終了するまでreturn値を返す訳ないと気がつきました。

だから,

go func_xxxx()

は、

go i:= finc_xxxx()

もダメだし

i := go func_xxxx()

もダメということで ―― では、スレッドの中の情報にどうやってアクセスすればいいかが、分かりません。

とすれば、スレッド側で送受信機能を持たせることになるのかなぁ、と思って、以下のようなコードを書いてみました。

package main

import (
	"fmt"
	"sync"
)

type BUS struct {
	number int
}

func bus_func(i int, wg *sync.WaitGroup, ch chan int) {
	defer wg.Done()

	bus := BUS{}
	bus.number = i

	pointer_bus := &bus

	fmt.Println(pointer_bus)

	for {
		select {
		case v := <-ch:
			fmt.Println(i, v)
		}
	}

}

func main() {
	var wg sync.WaitGroup
	defer wg.Wait()

	c := make(chan int)

	// バスエージェントの生成 3台
	for i := 0; i < 3; i++ {
		wg.Add(1)

		go bus_func(i, &wg, c)
	}

	// バスエージェントにメッセージを送る

	c <- 50
	c <- 30
	c <- 10

	c <- 50
	c <- 30
	c <- 10

	c <- 50
	c <- 30
	c <- 10

}

ただ、この場合、cチャネルは適当に投げられるので、どのオブジェクトにメッセージに届くか分からないので、もう少し工夫をしてみます。

package main

import (
	"fmt"
	"sync"
)

type BUS struct {
	number int
}

func bus_func(i int, wg *sync.WaitGroup, ch chan int) {
	defer wg.Done()

	bus := BUS{}
	bus.number = i

	pointer_bus := &bus

	fmt.Println(pointer_bus)

	for {
		select {
		case v := <-ch:
			fmt.Println(i, v)
		}
	}

}

//var c = make([]chan int, 3) // 間違い

var c [3]chan int // チャネルをグローバル変数で置く方法の、現時点での正解

// var c []chan int  これは実行時にエラーとなる

func main() {
	var wg sync.WaitGroup
	defer wg.Wait()

	//c := make(chan int)

	// バスエージェントの生成 3台
	for i := 0; i < 3; i++ {
		wg.Add(1)

		c[i] = make(chan int)
		go bus_func(i, &wg, c[i])
	}

	// バスエージェントにメッセージを送る

	c[0] <- 50
	c[1] <- 30
	c[2] <- 10

	c[0] <- 50
	c[1] <- 30
	c[2] <- 10

	c[0] <- 50
	c[1] <- 30
	c[2] <- 10

}