Rumah >pembangunan bahagian belakang >Golang >Lulus tatasusunan 2D dari Pergi ke C menggunakan runtime.Pinner

Lulus tatasusunan 2D dari Pergi ke C menggunakan runtime.Pinner

PHPz
PHPzke hadapan
2024-02-12 17:51:05614semak imbas

Lulus tatasusunan 2D dari Pergi ke C menggunakan runtime.Pinner

Kandungan soalan

Saya cuba menghantar tatasusunan 2D daripada Pergi ke beberapa fungsi C void foo(in **float, out *double)。因为我想要这个 C 函数的包装器,所以我希望 Go 函数具有像 func FooWrapper([][]float32) []float64 ditakrifkan seperti ini. Pelaksanaan yang paling mudah tetapi tidak begitu cekap ialah memperuntukkan semua memori melalui C yang disenaraikan di bawah:

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

Adakah pelaksanaan ini selamat? Bolehkah saya menghantar penunjuk kepada resultdata? Setahu saya, penunjuk ini akan disematkan kerana ia dihantar ke fungsi C.

Tetapi saya ingin memperuntukkan lebih sedikit memori dan hanya menggunakan semula memori Go, saya sudah tahu tentang panggilan runtime.Pinner ,它使指针固定直到 runtime.Pinner.Unpin(). Saya cuba menulis pelaksanaan lain menggunakan 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>

Tetapi, malangnya, kod ini tidak berfungsi

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?)

Adakah saya menggunakan runtime.Pinner salah (setahu saya saya boleh menyemat data hirisan)? Atau terdapat pepijat lain dalam kod ini. Adakah terdapat beberapa pelaksanaan menghantar tatasusunan 3d (4d dll.) kepada fungsi C selain memperuntukkan dan menyalin semua data ke memori C?

Penyelesaian

Saya jumpa jawapan kepada masalah saya. Menggunakan malloc adalah berbahaya kerana apabila saya cuba menulis penunjuk Go ke memori C, GC boleh mengenali memori yang tidak dimulakan sebagai memori "buruk", jadi jika saya menukar malloc kepada calloc tidak akan ada masalah. Sudah tentu ini bukan penyelesaian terbaik, adalah lebih baik untuk memperuntukkan memori dalam Go kerana ia lebih pantas dan selamat.

Semua perbincangan di sini一个>.

Atas ialah kandungan terperinci Lulus tatasusunan 2D dari Pergi ke C menggunakan runtime.Pinner. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:stackoverflow.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam