Goroutines 在 cgo 和 go 的不同堆栈中运行:
C 对 Go 的调用约定或可增长堆栈一无所知,因此对 C 代码的调用必须记录 goroutine 堆栈的所有细节,切换到 C 堆栈,并运行不知道如何调用的 C 代码,或者负责程序的更大的 Go 运行时。
是否有可能触发它们之间共享的变量或类型的数据竞争?
最近,我在初始化切片时遇到错误,例如:
package controlcan
import "C"
cReceive := make([]C.struct__CAN_OBJ, 2500)
或者
package main
import "controlcan"
pReceive := make([]controlcan.CanObj, 2500)
他们俩都随机抱怨“意外故障地址”错误:
unexpected fault address 0xffffffffffffffff
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xffffffffffffffff pc=0x41c65d]
goroutine 41 [running]:
runtime.throw(0xcc969a, 0x5)
/usr/local/go/src/runtime/panic.go:619 +0x88 fp=0xc0428ffb38 sp=0xc0428ffb18 pc=0x42d0b8
runtime.sigpanic()
/usr/local/go/src/runtime/signal_windows.go:170 +0x13a fp=0xc0428ffb68 sp=0xc0428ffb38 pc=0x43fcca
runtime.gcMarkRootPrepare()
/usr/local/go/src/runtime/mgcmark.go:72 +0x5d fp=0xc0428ffb70 sp=0xc0428ffb68 pc=0x41c65d
runtime.gcStart(0x0, 0x1, 0x0, 0x0)
/usr/local/go/src/runtime/mgc.go:1350 +0x30f fp=0xc0428ffba0 sp=0xc0428ffb70 pc=0x419b6f
runtime.mallocgc(0x10000, 0xc54660, 0xc0422ee001, 0xc0423ded60)
/usr/local/go/src/runtime/malloc.go:803 +0x448 fp=0xc0428ffc40 sp=0xc0428ffba0 pc=0x411c48
runtime.makeslice(0xc54660, 0x9c4, 0x9c4, 0xc04202ce00, 0xc04202c000, 0x411b23)
/usr/local/go/src/runtime/slice.go:61 +0x7e fp=0xc0428ffc70 sp=0xc0428ffc40 pc=0x43fffe
controlcan.Receive(0x4, 0x0, 0x0, 0xc04267e000, 0x9c4, 0x9c4, 0x64, 0x0, 0x0, 0x0)
/media/sf_GOPATH0/src/controlcan/controlcan.go:262 +0x75 fp=0xc0428ffd70 sp=0xc0428ffc70 pc=0xa0d795
posam/protocol/usbcan.(*Channel).receive(0xc04229d490)
/media/sf_GOPATH0/src/posam/protocol/usbcan/usbcan.go:469 +0x536 fp=0xc0428fffd8 sp=0xc0428ffd70 pc=0xa10926
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc0428fffe0 sp=0xc0428fffd8 pc=0x457531
created by posam/protocol/usbcan.(*Channel).Start
/media/sf_GOPATH0/src/posam/protocol/usbcan/usbcan.go:242 +0x3aa
更新
controlcan
是一个包装器包,它将定义在Golang 友好的函数.dll
或库中的函数封装起来,例如,向 CAN 设备发送消息或从 CAN 设备接收消息。.so
IMO,在controlcan
包内和其他包中导入切片初始化语句的数据竞争真的很奇怪。
在Receive
函数中,第一行声明了一个切片cReceive
,如上所述,我随机得到了错误。我认为原因unexpected fault address
是数据竞争而不是内存损坏,但这里需要的资源只是类型C.struct__VCI_CAN_OBJ
,而不是任何变量。我希望我错了。
更糟糕的是,CanObj
在其他包中使用的 typeusbcan.go
仍然可能触发错误,例如pReceive
. 以前,我怀疑原因可能是 的常数2500
,因为原始语句是cReceive := make([]C.struct__VCI_CAN_OBJ, FRAME_LENGTH_OF_RECEPTION)
。但是当我2500
直接将其更改为时,错误仍然发生。
controlcan.go
package controlcan
import "C"
import (
"fmt"
"runtime"
"unsafe"
)
const (
FRAME_LENGTH_OF_RECEPTION = 2500
)
type CanObj struct { // <- accessable for other packages/goroutines
ID int
TimeStamp int
TimeFlag int
SendType byte
RemoteFlag byte
ExternFlag byte
DataLen byte
Data [8]byte
Reserved [3]byte
}
func Receive(
devType int,
devIndex int,
canIndex int,
pReceive []CanObj,
waitTime int,
) (count int, err error) {
cReceive := make([]C.struct__VCI_CAN_OBJ, 2500) // unexpected fault address
cCount := C.VCI_Receive(
C.uint(devType),
C.uint(devIndex),
C.uint(canIndex),
(*C.struct__VCI_CAN_OBJ)(unsafe.Pointer(&cReceive)),
C.uint(FRAME_LENGTH_OF_RECEPTION),
C.int(waitTime),
)
// ...
}
usbcan.go
package usbcan
import "controlcan"
func (c *Channel) receive() {
ticker := time.NewTicker(100 * time.Millisecond)
defer ticker.Stop()
for _ = range ticker.C {
pReceive := make([]controlcan.CanObj, 2500) // unexpected fault address
count, err := controlcan.Receive(
c.DevType,
c.DevIndex,
c.CanIndex,
pReceive,
100,
)
// ...
更新 2:
我将cReceive
创建从 Go 移动到 Cgo,从Kenny Grant窃取,并且 line 的 make-slice 错误cReceive
得到解决。
package controlcan
// static VCI_CAN_OBJ** makeCanObjArray(){
// return calloc(sizeof(VCI_CAN_OBJ*), 2500);
// }
// static void freeCanObjArray(VCI_CAN_OBJ **canObjArray){
// int i;
// for (i=0; i<2500;i++)
// free(canObjArray[i]);
// free(canObjArray);
// }
import "C"
func Receive(
devType int,
devIndex int,
canIndex int,
pReceive []CanObj,
waitTime int,
) (count int, err error) {
cReceive := C.makeCanObjArray()
defer C.freeCanObjArray(cReceive)
// ...
而且我仍然无法弄清楚创建时会发生什么pReceive
:
pReceive := make([]controlcan.CanObj, 2500)
unexpected fault address 0xffffffffffffffff
fatal error: fault
[signal 0xc0000005 code=0x0 addr=0xffffffffffffffff pc=0x41c65d]
goroutine 28 [running]:
runtime.throw(0xcc969a, 0x5)
/usr/local/go/src/runtime/panic.go:619 +0x88 fp=0xc04275bc38 sp=0xc04275bc18 pc=0x42d0b8
runtime.sigpanic()
/usr/local/go/src/runtime/signal_windows.go:170 +0x13a fp=0xc04275bc68 sp=0xc04275bc38 pc=0x43fcca
runtime.gcMarkRootPrepare()
/usr/local/go/src/runtime/mgcmark.go:72 +0x5d fp=0xc04275bc70 sp=0xc04275bc68 pc=0x41c65d
runtime.gcStart(0x0, 0x1, 0x0, 0x0)
/usr/local/go/src/runtime/mgc.go:1350 +0x30f fp=0xc04275bca0 sp=0xc04275bc70 pc=0x419b6f
runtime.mallocgc(0x1a000, 0xc54520, 0x1, 0xa10101)
/usr/local/go/src/runtime/malloc.go:803 +0x448 fp=0xc04275bd40 sp=0xc04275bca0 pc=0x411c48
runtime.makeslice(0xc54520, 0x9c4, 0x9c4, 0xc0420162a0, 0x8, 0x8)
/usr/local/go/src/runtime/slice.go:61 +0x7e fp=0xc04275bd70 sp=0xc04275bd40 pc=0x43fffe
posam/protocol/usbcan.(*Channel).receive(0xc04213fdc0)
/media/sf_GOPATH0/src/posam/protocol/usbcan/usbcan.go:464 +0x4f0 fp=0xc04275bfd8 sp=0xc04275bd70 pc=0xa108e0
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc04275bfe0 sp=0xc04275bfd8 pc=0x457531
created by posam/protocol/usbcan.(*Channel).Start
/media/sf_GOPATH0/src/posam/protocol/usbcan/usbcan.go:242 +0x3aa