gpt4 book ai didi

go - `make(chan _, _)` 是原子的吗?

转载 作者:数据小太阳 更新时间:2023-10-29 03:13:19 26 4
gpt4 key购买 nike

修改消费者正在读取的 channel 是否线程安全?

考虑以下代码:

func main(){
channel := make(chan int, 3)
channel_ptr := &channel

go supplier (channel_ptr)
go consumer (channel_ptr)

temp = *channel_ptr
// Important bit
*channel_ptr = make(chan int, 5)

more := true
for more{
select {
case msg := <-temp:
*channel_ptr <- msg
default:
more = false
}
}
// Block main indefinitely to keep the children alive
<-make(chan bool)
}

func consumer(c *chan int){
for true{
fmt.Println(<-(*c))
}
}

func supplier(c *chan int){
for i :=0; i < 5; i ++{
(*c)<-i
}
}

如果 channel 和 make 以我希望的方式工作,我应该获得以下属性:

  1. 程序总是输出 0 1 2 3 4
  2. 程序永远不会因尝试从未初始化的 channel 读取而 panic (IE,我标记为重要位的部分是原子的)

从几次测试运行来看,这似乎是真的,但我无法在文档中的任何地方找到它,我担心微妙的竞争条件。

更新

是的,我所做的不起作用。这个线程可能在这一点上被埋没了,但是有人知道如何动态调整缓冲 channel 的大小吗?

最佳答案

它不是线程安全的。

如果您使用 -race 标志运行以使用 race detector ,你会看到错误:

$ run -race t.go
==================
WARNING: DATA RACE
Write at 0x00c420086018 by main goroutine:
main.main()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:14 +0x128

Previous read at 0x00c420086018 by goroutine 6:
main.supplier()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:37 +0x51

Goroutine 6 (running) created at:
main.main()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:9 +0xb4
0
==================
1
2
3
==================
WARNING: DATA RACE
Read at 0x00c420086018 by goroutine 6:
main.supplier()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:37 +0x51

Previous write at 0x00c420086018 by main goroutine:
main.main()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:14 +0x128

Goroutine 6 (running) created at:
main.main()
/Users/kjk/src/go/src/github.com/kjk/go-cookbook/start-mysql-in-docker-go/t.go:9 +0xb4
==================
4

根据经验,永远不要将 channel 作为指针传递。 Channel 在内部已经是一个指针。

退后一步:我不明白你想要达到什么目的。

我想您尝试将 channel 作为指针传递是有原因的。在 Go 中使用 channel 的模式是:你创建它一次,然后将它作为值传递。您不会将指针传递给它,也不会在创建后对其进行修改。

在您的示例中,问题在于您有一 block 共享内存(channel_ptr 指向的内存地址)并且您在一个线程中写入该内存,而其他线程读取它。这就是数据竞赛。

它不是特定于 channel 的,如果它是指向 int 的指针并且两个线程正在修改 int 的值,您也会遇到同样的问题。

关于go - `make(chan _, _)` 是原子的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44974701/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com