首頁 >後端開發 >Golang >使用runtime.Pinner將二維數組從Go傳遞到C

使用runtime.Pinner將二維數組從Go傳遞到C

PHPz
PHPz轉載
2024-02-12 17:51:05614瀏覽

使用runtime.Pinner將二維數組從Go傳遞到C

問題內容

我試著將二維陣列從Go 傳遞到某個C 函數void foo(in **float, out *double)。因為我想要這個 C 函數的包裝器,所以我希望 Go 函數有像 func FooWrapper([][]float32) []float64 這樣的定義。最簡單但效率不高的實作是透過下面列出的 C 來分配所有記憶體:

<code>func FooWrapper(values [][]float32) []float64 {
    totalObj := len(values)
    totalParams := len(values[0])
    results := make([]float64, totalObj)

    ptrArrLength := uintptr(totalObj) * cPointerSize
    paramArrLength := uintptr(totalParams) * cFloatSize

    ptr := C.malloc(C.size_t(ptrArrLength + paramArrLength*uintptr(totalObj)))
    defer C.free(ptr)

    ptrSlice := unsafe.Slice((**C.float)(ptr), totalObj)
    for i, obj := range values {
        paramArrPtr := (*C.float)(unsafe.Add(ptr, ptrArrLength+uintptr(i)*paramArrLength))
        ptrSlice[i] = paramArrPtr

        paramSlice := unsafe.Slice(paramArrPtr, totalParams)
        for j, param := range obj {
            paramSlice[j] = (C.float)(param)
        }
    }

    C.foo((**C.float)(ptr), (*C.double)(&results[0]))

    return results
}
</code>

這樣的實作安全嗎?我可以傳遞result資料的指標嗎?據我所知,這個指標將被固定,因為它傳遞給了 C 函數。

但是我想分配更少的內存,只是重用Go內存,我已經了解了runtime.Pinner ,它使指針固定直到runtime.Pinner.Unpin() 調用。我嘗試使用 pinner 編寫另一個實作:

<code>func FooWrapper(values [][]float32) []float64 {
    length := len(values)
    results := make([]float64, length)

    pinner := runtime.Pinner{}
    defer pinner.Unpin()

    arr := (**C.float)(C.malloc(C.size_t(uintptr(length) * cPointerSize)))
    defer C.free(unsafe.Pointer(arr))
    slice := unsafe.Slice(arr, length)
    for i, v := range values {
        pinner.Pin(&v[0])
        slice[i] = (*C.float)(&v[0])
    }

    C.foo(arr, (*C.double)(&results[0]))

    return results
}
</code>

但是,不幸的是,這段程式碼不起作用

runtime: pointer 0xc016ecbfc0 to unused region of span span.base()=0xc016eca000 span.limit=0xc016ecbfa0 span.state=1
fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

我使用runtime.Pinner是否錯誤(據我所知,我可以固定切片資料)?或者這段程式碼還有另一個錯誤。除了將所有資料分配和複製到 C 記憶體之外,是否有一些將 3d(4d 等)數組傳遞給 C 函數的實現?

解決方法

我找到了問題的答案。使用 malloc 是危險的,因為當我嘗試將 Go 指標寫入 C 記憶體時,GC 可以將未初始化的記憶體識別為「壞」內存,因此如果我將 malloc 更改為 calloc 就不會出現問題。當然這不是最好的解決方案,最好在 Go 中分配內存,因為它更快、更安全。

所有討論此處一个>.

#

以上是使用runtime.Pinner將二維數組從Go傳遞到C的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除