A question about channels

Hi,

I hope this isn’t a boneheaded question. I have searched in this forum but haven’t seen quite what I am looking for. This post about possible race conditions seems a likely fit.

I’ve been looking at channels on golangdocs.com, sending custom data via channels. I have made one tiny change, adding a Printf statement to the called function. I’ll paste the whole code here so it is easy to see.

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
}

func SendPerson(ch chan Person, p Person) {
	ch <- p
	fmt.Printf("SendPerson %v\n", p)
}

func main() {

	p := Person{"John", 23}

	ch := make(chan Person)

	go SendPerson(ch, p)

	name := (<-ch).Name
	fmt.Println(name)
}

If I run this code a few times I usually see just John. Sometimes I see:

SendPerson {John 23}
John

I don’t quite understand why. I thought this was an error on my part as I should have put the Printf statement in the called function before the channel handling part because I wanted to see what I was receiving (that was the purpose of adding the Printf in the first place). But then I thought about it a bit more. Why do I see this sometimes? I would expect to see it always or never, but not sometimes seemingly at random. I am not sure if this is connected to being buffered or unbuffered.

Can somebody point me in the right direction?

Many thanks,
John.

Hi @MrJohn
The SendMessage function (and goroutine) ends before it can print the message.
Try to print and then send the message to the channel.

When the Main function finalize, it kills all the others goroutines.
It’s like a race condition.

Hi @GonzaSaya,

Thanks, I guessed it was a race condition. But I didn’t quite understand why.

Thanks again.
John.

I am really do not understand your question fully. It print “John” becase you are taking only that part in

name := (<-ch).Name
fmt.Println(name)

So if you want all the structure in the channel, just

perso := <-ch
fmt.Println(perso)

But as I say before i am sure if i understand your question. Let me know…

Yamil

gorountine runtime is uncertain.
try to this, it woundn’t until block that one msgs be send to channle
for p:=range ch{
fmt.Println(p.name)
}

You can change your approach to send message into channel to, because you guarantee that your message are logged, of course if your program running in background, if you only can just run and down, so you can block this wait the message into channel or use a sync.WaitGroup

package main

import (
	"fmt"
)

type Person struct {
	Name string
	Age  int
	Message chan string
}

func NewPerson(name string, age int) *Person {
	return &Person{
		Name: name,
		Age: age,
		Message: make(chan string),
	}
}

func (s *Person) Send(ch chan *Person) {
	s.Message <- "The message was sent"

	ch <- s
}

func (s *Person) ReadMessage() {
	go func(){
		for m := range s.Message {
			fmt.Println(m)
		}
	}()
}

func main() {
	p := NewPerson("John", 23)
	p. ReadMessage()

	ch := make(chan *Person)
	go p.Send(ch)

	fmt.Println((<-ch).Name)
}

https://play.golang.com/p/D4akv-iVII__i

gorountine runtime is uncertain.

Aha. I think that answers it.

Many thanks for the code. It does seem far more complicated than the original example.

I have been programming on and off with go for a while now, but haven’t really done anything with channels. I was a bit surprised at pretty much my first look at them that I was getting a race condition of some sort, or at least not expected behaviour.

I understand, yes, when you run fmt.Print etc. there is no guarantee that it will be executed because there is no order of execution of the goroutines, and also when your main goroutine finishes the others will also be finished, which can happen if your print never appears