Golang中如何解决goroutine运行时错误
Golang中如何解决goroutine运行时错误 你好,
我在执行我的Go应用程序时遇到了一个错误。Go应用程序调用了一个插件方法,并因以下堆栈信息而崩溃。有人能帮忙修复这个错误吗?
runtime: unexpected return pc for testmethod called from 0x7fdda7006de0
stack: frame={sp:0xc000d09850, fp:0xc000d09858} stack=[0xc000d04000,0xc000d0c000)
000000c000d09750: 00007fddb3e17d2f <runtime.cgocallbackg+239> 00007fddb3e17ba5 <runtime.cgocall+101>
000000c000d09760: 000000c000d097e8 000000c000d097a8
000000c000d09770: 00007fddb3e67e56 <runtime.exitsyscallfast+214> 000000c000177000
000000c000d09780: 000000c000d097b8 00007fddb3e674de <runtime.reentersyscall+126>
000000c000d09790: 000000c0012ead80 0000000300000002
000000c000d097a0: 000000c0012ead80 000000c000d097d8
000000c000d097b0: 00007fddb3e67cc9 <runtime.exitsyscall+393> 000000c000d097d8
000000c000d097c0: 00007fddb3e676e6 <runtime.entersyscall+38> 00007fddb3e17ba5 <runtime.cgocall+101>
000000c000d097d0: 000000c000d097e8 00007fddb3e9c7ff <runtime.asmcgocall+63>
000000c000d097e0: 00007fddb3e17bc9 <runtime.cgocall+137> 00007fddb43c0070
000000c000d097f0: 000000c000d09850 000000c000000000
000000c000d09800: 0000000000d09830 <github.com/microcosm-cc/bluemonday.UGCPolicy+2448> 0000000001ee2620
000000c000d098d0: 000000c001801f88 00007fddac071698
000000c000d098e0: 000000c001801f00 0000000000000000
000000c000d098f0: 0000000000000000 0000000000000001
000000c000d09900: 0000000000000000 0000000000000000
000000c000d09910: 00007fddac350c28 000000c001801f00
000000c000d09920: 0000000000000005 0000000000000000
000000c000d09930: 0000000000000000 00007fddac350c28
000000c000d09940: 0000000000000001 0000000000000000
000000c000d09950: 0000000000000000
fatal error: unknown caller pc
runtime stack:
runtime.throw(0x12ebd52, 0x11)
/usr/local/go/src/runtime/panic.go:1116 +0x74
runtime.gentraceback(0xffffffffffffffff, 0xffffffffffffffff, 0x0, 0xc0012ead80, 0x0, 0x0, 0x7fffffff, 0x7fdd5e7fbbb8, 0x0, 0x0, …)
/usr/local/go/src/runtime/traceback.go:273 +0x1aac
runtime.scanstack(0xc0012ead80, 0xc000547e98)
/usr/local/go/src/runtime/mgcmark.go:844 +0x165
runtime.markroot.func1()
/usr/local/go/src/runtime/mgcmark.go:245 +0xc6
runtime.markroot(0xc000547e98, 0xea)
/usr/local/go/src/runtime/mgcmark.go:218 +0x345
runtime.gcDrain(0xc000547e98, 0x3)
/usr/local/go/src/runtime/mgcmark.go:1108 +0x146
runtime.gcBgMarkWorker.func2()
/usr/local/go/src/runtime/mgc.go:1958 +0x87
runtime.systemstack(0x1e7e050)
/usr/local/go/src/runtime/asm_amd64.s:370 +0x63
runtime.mstart()
/usr/local/go/src/runtime/proc.go:1116
goroutine 25 [GC worker (idle)]:
runtime.systemstack_switch()
/usr/local/go/src/runtime/asm_amd64.s:330 fp=0xc000186f60 sp=0xc000186f58 pc=0x8d1be0
runtime.gcBgMarkWorker(0xc000546800)
/usr/local/go/src/runtime/mgc.go:1945 +0x1ea fp=0xc000186fd8 sp=0xc000186f60 pc=0x87f9ca
runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:1374 +0x1 fp=0xc000186fe0 sp=0xc000186fd8 pc=0x8d39c1
created by runtime.gcBgMarkStartWorkers
/usr/local/go/src/runtime/mgc.go:1839 +0x85
goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x7fddac3c5798, 0x72, 0x0)
/usr/local/go/src/runtime/netpoll.go:220 +0x65
internal/poll.(*pollDesc).wait(0xc00081e798, 0x72, 0x0, 0x0, 0x12dc0f0)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x47
internal/poll.(*pollDesc).waitRead(…)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc00081e780, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:394 +0x1fc
net.(*netFD).accept(0xc00081e780, 0x7667f3ba6dfc7c5a, 0x0, 0x0)
/usr/local/go/src/net/fd_unix.go:172 +0x45
net.(*TCPListener).accept(0xc00086f340, 0x60e5b630, 0xc0002f7c58, 0x8faa28)
/usr/local/go/src/net/tcpsock_posix.go:139 +0x34
net.(*TCPListener).Accept(0xc00086f340, 0xc0002f7ca8, 0x18, 0xc000000180, 0xb7d954)
/usr/local/go/src/net/tcpsock.go:261 +0x66
net/http.(*Server).Serve(0xc0002e8000, 0x192dc00, 0xc00086f340, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:2937 +0x286
net/http.(*Server).ListenAndServe(0xc0002e8000, 0xc0002e8000, 0xc00086f320)
/usr/local/go/src/net/http/server.go:2866 +0xb9
net/http.ListenAndServe(…)
/usr/local/go/src/net/http/server.go:3120
main.main()
goroutine 22 [select, 50 minutes]:
database/sql.(*DB).connectionOpener(0xc0001bfad0, 0x1932fc0, 0xc0005a7b80)
/usr/local/go/src/database/sql/sql.go:1126 +0xe8
created by database/sql.OpenDB
/usr/local/go/src/database/sql/sql.go:740 +0x13f
goroutine 11340 [IO wait]:
internal/poll.runtime_pollWait(0x7fddac3c4d18, 0x72, 0x191f800)
/usr/local/go/src/runtime/netpoll.go:220 +0x65
internal/poll.(*pollDesc).wait(0xc0007cc418, 0x72, 0xc000637d00, 0x1, 0x1)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x47
internal/poll.(*pollDesc).waitRead(…)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc0007cc400, 0xc000637db1, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:159 +0x1b1
net.(*netFD).Read(0xc0007cc400, 0xc000637db1, 0x1, 0x1, 0xbf5152, 0xc0001b4ae0, 0xc00070af80)
/usr/local/go/src/net/fd_posix.go:55 +0x51
net.(*conn).Read(0xc000d14018, 0xc000637db1, 0x1, 0x1, 0x0, 0x0, 0x0)
/usr/local/go/src/net/net.go:182 +0x90
net/http.(*connReader).backgroundRead(0xc000637da0)
/usr/local/go/src/net/http/server.go:690 +0x5a
created by net/http.(*connReader).startBackgroundRead
/usr/local/go/src/net/http/server.go:686 +0xd5
goroutine 10891 [select]:
github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher.func1(0xc000c16360, 0xc0007e45a0, 0xc0002a84e0)
/root/go/pkg/mod/github.com/go-sql-driver/mysql@v1.5.0/connection.go:621 +0xbf
created by github.com/go-sql-driver/mysql.(*mysqlConn).startWatcher
/root/go/pkg/mod/github.com/go-sql-driver/mysql@v1.5.0/connection.go:618 +0xc8
goroutine 11381 [IO wait]:
internal/poll.runtime_pollWait(0x7fddac3c5178, 0x72, 0x191f800)
/usr/local/go/src/runtime/netpoll.go:220 +0x65
internal/poll.(*pollDesc).wait(0xc0007cc998, 0x72, 0xc00092e000, 0x1000, 0x1000)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x47
internal/poll.(*pollDesc).waitRead(…)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc0007cc980, 0xc00092e000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:159 +0x1b1
net.(*netFD).Read(0xc0007cc980, 0xc00092e000, 0x1000, 0x1000, 0xc000e02f00, 0x300000002, 0xc000e02f00)
/usr/local/go/src/net/fd_posix.go:55 +0x51
net.(*conn).Read(0xc000d14048, 0xc00092e000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
/usr/local/go/src/net/net.go:182 +0x90
net/http.(*connReader).Read(0xc000897d10, 0xc00092e000, 0x1000, 0x1000, 0x8, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:798 +0x1c2
bufio.(*Reader).fill(0xc000903ec0)
/usr/local/go/src/bufio/bufio.go:101 +0x105
bufio.(*Reader).ReadSlice(0xc000903ec0, 0xa, 0x1481128, 0xc001423988, 0x86e990, 0xc000d48a00, 0x100)
/usr/local/go/src/bufio/bufio.go:360 +0x3f
bufio.(*Reader).ReadLine(0xc000903ec0, 0xc001423990, 0xc0006d0000, 0x7fddacfd9c28, 0x0, 0x86f37a, 0x30)
/usr/local/go/src/bufio/bufio.go:389 +0x36
net/textproto.(*Reader).readLineSlice(0xc000c15ad0, 0xc000d48a00, 0x94404f, 0xc0007cc980, 0x0, 0xc0007cc980)
/usr/local/go/src/net/textproto/reader.go:58 +0x6e
net/textproto.(*Reader).ReadLine(…)
/usr/local/go/src/net/textproto/reader.go:39
net/http.readRequest(0xc000903ec0, 0x0, 0xc000d48a00, 0x0, 0x0)
/usr/local/go/src/net/http/request.go:1012 +0xac
net/http.(*conn).readRequest(0xc0003b94a0, 0x1932fc0, 0xc000082100, 0x0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:984 +0x19a
net/http.(*conn).serve(0xc0003b94a0, 0x1932fc0, 0xc000082100)
/usr/local/go/src/net/http/server.go:1851 +0x70d
created by net/http.(*Server).Serve
/usr/local/go/src/net/http/server.go:2969 +0x394
更多关于Golang中如何解决goroutine运行时错误的实战教程也可以访问 https://www.itying.com/category-94-b0.html
抱歉,是的,我会回复你的。
你能提供重现它的步骤吗?
你好 @skillian 能否请你回复我之前提出的问题?
崩溃并非每次都会发生,它非常罕见。没有重现崩溃的步骤。我正在调用一个插件方法。崩溃是随机发生的。下面这行信息每次都会出现:
/usr/local/go/src/runtime/asm_amd64.s:1374 +0x1 fp=0xc000186fe0 sp=0xc000186fd8 pc=0x8d39c1
created by runtime.gcBgMarkStartWorkers
ManojKumarChauhan:
我可以从Go函数中同时调用多个cgo函数(多线程)吗?
可以。
ManojKumarChauhan:
同样地,我可以从cgo函数中同时调用Go函数吗?
这很有趣;你的代码是在整个调用栈中在C和Go之间来回切换吗?这可能会有问题,因为Go的栈会增长并且可以被移动。我不确定如果其中混入了一些C栈会发生什么。我甚至不知道C栈和Go栈是否是同一个栈(我对cgo几乎没有任何经验)。
我理解在不复现问题的情况下很难找到原因。我对Go语言并不精通,所以想请教一些常见问题。我认为我可能没有遵循Go语言的基本规则。
我创建了一个插件并编写了一些Go函数。在插件中还使用了一个C语言库,从Go函数中调用cgo函数,并且在插件中编写了一些cgo函数。
我可以从Go函数中同时调用多个cgo函数(多线程)吗? 同样地,我可以从cgo函数中同时调用Go函数吗?
在大多数情况下,我在runtime.cgocall和proc.go:1116(mstart())以及runtime.systemstack_switch()中遇到错误。
这个错误通常发生在使用CGO调用插件时,栈帧信息不一致导致的。主要原因是插件中的函数指针与Go运行时的调用约定不匹配。
以下是几种可能的解决方案:
1. 使用runtime.KeepAlive确保CGO对象不被回收
import "runtime"
func callPlugin() {
// 调用插件函数
result := pluginFunc()
// 确保插件相关的资源在函数返回前不被GC回收
runtime.KeepAlive(pluginHandle)
}
2. 检查插件编译选项是否匹配 确保插件和主程序使用相同的编译标志:
// 构建插件时
// go build -buildmode=plugin -o plugin.so plugin.go
// 主程序加载插件
import "plugin"
func main() {
p, err := plugin.Open("plugin.so")
if err != nil {
panic(err)
}
sym, err := p.Lookup("Testmethod")
if err != nil {
panic(err)
}
testFunc, ok := sym.(func() error)
if !ok {
panic("unexpected type from module symbol")
}
err = testFunc()
if err != nil {
panic(err)
}
}
3. 使用sync.Pool管理CGO调用
import (
"sync"
"unsafe"
)
var cgoPool = sync.Pool{
New: func() interface{} {
// 初始化CGO资源
return initCGO()
},
}
func safeCall() {
cgoObj := cgoPool.Get().(unsafe.Pointer)
defer cgoPool.Put(cgoObj)
// 使用cgoObj调用插件函数
callWithCGO(cgoObj)
}
4. 设置GODEBUG环境变量调试
// 在程序启动前设置
func init() {
os.Setenv("GODEBUG", "cgocheck=0")
}
// 或者运行时设置
func main() {
debug.SetTraceback("system")
// ... 程序逻辑
}
5. 使用runtime.LockOSThread绑定线程
func callPluginSafely() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
// 调用插件函数
pluginFunc()
}
6. 检查内存对齐问题
import "unsafe"
// 确保C结构体与Go结构体对齐
/*
#include <stddef.h>
typedef struct {
int64_t field1;
void* field2;
} CStruct;
*/
import "C"
type GoStruct struct {
Field1 int64
Field2 unsafe.Pointer
}
// 验证大小和对齐
var _ = [unsafe.Sizeof(GoStruct{})]byte{}
var _ = [C.sizeof_CStruct]byte{}
7. 使用cgo.Handle进行安全的回调
/*
#include <stdint.h>
extern void goCallback(uintptr_t handle);
static void callGo(uintptr_t handle) {
goCallback(handle);
}
*/
import "C"
import "runtime/cgo"
func setupCallback() {
h := cgo.NewHandle(func() {
// 回调逻辑
})
C.callGo(C.uintptr_t(h))
}
8. 确保插件接口定义正确
// 插件接口定义
type Plugin interface {
Testmethod() error
Cleanup()
}
// 安全调用模式
func safePluginCall(p Plugin) error {
defer func() {
if r := recover(); r != nil {
// 处理panic
}
}()
err := p.Testmethod()
p.Cleanup()
return err
}
这个错误通常与CGO调用约定、内存管理或GC相关。需要确保插件函数遵循Go的调用约定,并且在CGO调用期间保持相关对象的存活。

