S
S
SSSSTTTTAAAASSSS2021-07-08 20:38:17
go
SSSSTTTTAAAASSSS, 2021-07-08 20:38:17

Working with goroutines?

Good afternoon.
A beginner in GO has a task with 2 goroutines: one writes a pointer to the values ​​in the slice to the channel, the second reads them.
https://play.golang.org/p/wcNBsu1pjYK
A solution is required for the program to work correctly and return slice values.
As far as it is clear from the training materials, the goroutine should block after writing to the channel until it is read. I tried to make an unbuffered channel in the program, but all the same, the values ​​\u200b\u200bjump.
https://play.golang.org/p/yzRhQOdR8La
At the moment, it has been possible to solve it only by slowing down the goroutine that writes to the channel:
https://play.golang.org/p/r4pqhh0tPPW
But I understand that the solution is wrong.

Perhaps someone can explain what I'm missing.
Thanks in advance

Answer the question

In order to leave comments, you need to log in

1 answer(s)
E
Evgeny Mamonov, 2021-07-08
@SSSSTTTTAAAASSSS

There are several options for solving the problem

pass not a pointer, but a value

package main

import (
  "fmt"
  "time"
)

var c = make(chan int, 3)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

func main() {
  fmt.Println("Hello, playground")
  go save()
  go read()
  time.Sleep(3 * time.Second)
}

func save() {
  for _, val := range data {
    c <- val
  }
}

func read() {
  for {
    val := <-c
    fmt.Println("read:", val)
  }
}

copy a value and pass a pointer to that value

package main

import (
  "fmt"
  "time"
)

var c = make(chan *int)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

func main() {
  fmt.Println("Hello, playground")
  go save()
  go read()
  time.Sleep(3 * time.Second)
}

func save() {
  for _, val := range data {
          v := val
    c <- &v
  }
}

func read() {
  for {
    val := <-c
    fmt.Println("read:", *val)
  }
}

pass the correct pointer to the data element

package main

import (
  "fmt"
  "time"


var c = make(chan *int, 5)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

func main() {
  fmt.Println("Hello, playground")
  go save()
  go read()
  time.Sleep(3 * time.Second)
}

func save() {
  for i := range data {
    c <- &data[i]
  }
}

func read() {
  for {
    val := <-c
    fmt.Println("read:", *val)
  }
}


The problem in the solution arises because you pass the same pointer at each iteration of the loop, and when the second goroutine reads, the writing goroutine already writes data on this pointer to this memory area, for this reason the same data appears when outputting.
Here is an example that will show that the address is always the same
package main

import (
  "fmt"
  "time"
)

var c = make(chan *int, 5)
var data = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

func main() {
  fmt.Println("Hello, playground")
  go save()
  go read()
  time.Sleep(3 * time.Second)
}

func save() {
  for _, val := range data {
    c <- &val
    fmt.Printf("write: %v\n", &val)
  }
}

func read() {
  for {
    val := <-c
    fmt.Println("read:", *val)
  }
}

The output will be like this (the address is the same)
Hello, playground
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
write: 0xc000094000
...

And in such an implementation (2nd example)
func save() {
  for _, val := range data {
    v := val
    c <- &v
    fmt.Printf("write: %v\n", &v)
  }
}

here the output will be like this (each time a new piece of memory)
Hello, playground
write: 0xc000094000
write: 0xc000094010
write: 0xc000094018
write: 0xc000094020
write: 0xc000094028
write: 0xc000094030

In the third option, there will also be different pointers.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question