Go interface的结构以及在并发过程中赋值的问题

1 经常使用C语言的同学,知道指针在赋值的过程中是一个原子写的过程,因为指针是一个机器字(machine word),这是一个原子写的过程。同样在java的的变量赋值也是类似的,因为在Java中除了八种基本类型,其他的所有类型也是一个header对象的指针

2 在Go语言中变量的赋值是Copy语义的,但是在赋值的过程中可能会有一些小的hack行为,和我们通常理解的指针赋值不一样。例如我们把一个结构体的指针赋值给一个接口。

代码如下:

package main

import "fmt"


func main() {
	ben := &Ben{10, "Ben"}
	jerry := &Jerry{"Jerry"}

	var maker IceCreamMaker

	var loop0,loop1 func()

	maker = jerry
	loop0 = func() {
		maker = ben
		go loop1()
	}

	loop1 = func() {
		maker = jerry
		go loop0()
	}

	go loop0()

	for{
		maker.Hello()
	}

}

type IceCreamMaker interface {
	Hello()
}

type Ben struct {
	id   int
	name string
}

type Jerry struct {
	name string
}

func (ben *Ben) Hello() {
	fmt.Printf(`Ben said,"Hello my name is %s"`, ben.name)
	fmt.Println()
}

func (jerry *Jerry) Hello() {
	fmt.Printf(`Jerry said,"Hello my name is %s"`, jerry.name)
	fmt.Println()
}

以上代码在运行的过程中可能会出现

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x5 pc=0x8e54d3]

的panic。究其原因就是goroutin在并发的给maker接口变量赋值的过程中不是一个原子的行为。Go接口不是我们在其他语言中理解的一个无结构的成员。

看以看到接口是有两个字段的 ,一部分指向结构一部分指向数据。所以我们在把一个指针赋值给一个接口的过程中go的编译器会通过指针自动分析出结构和数据部分,然后就有了2次的写的行为,在并发过程中就会产生interface变量的数据的破坏,产生runtime的panic. 由于Ben和Jerry这两个结构体不是一样的导致内存布局也不相同。我们假设在并发的过程中maker变量的Type字段指向了Bob结构体但是Data却是指向了Jerry的数据,此时runtime根据Bob的内存布局去在jerry中寻找name就会产生未定义的行为

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值