dousi8931 2017-07-07 15:34
浏览 61

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

Is it thread-safe to modify the channel that a consumer is reading from?

Consider the following code:

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
    }
}

If channels and make work the way that I want them to, I should get the following properties:

  1. The program always outputs 0 1 2 3 4
  2. The program will never panic from trying to read from a non-initialized channel (IE, the part I labelled Important bit is atomic)

From several test runs, this seems to be true, but I can't find it anywhere in the documentation and I'm worried about subtle race conditions.

Update

Yeah, what I was doing doesn't work. This thread is probably buried at this point, but does anybody know how to dynamically resize a buffered channel?

  • 写回答

1条回答 默认 最新

  • drtj40036 2017-07-08 07:05
    关注

    It's not thread safe.

    If you run with -race flag to use race detector, you'll see the bug:

    $ 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
    

    As a rule of thumb, you should never pass channel as a pointer. Channel already is a pointer internally.

    Stepping back a bit: I don't understand what you're trying to achieve.

    I guess there's a reason you're trying to pass a channel as a pointer. The pattern of using channels in Go is: you create it once and you pass it around as value. You don't pass a pointer to it and you never modify it after creation.

    In your example the problem is that you have a shared piece of memory (memory address pointed to by channel_ptr) and you write to that memory in one thread while some other thread reads it. That's data race.

    It's not specific to a channel, you would have the same issue if it was pointer to an int and two threads were modifying the value of an int.

    评论

报告相同问题?

悬赏问题

  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗
  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值