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

PHPz
Lepaskan: 2024-02-12 17:51:05
ke hadapan
560 orang telah melayarinya

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>
Salin selepas log masuk

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>
Salin selepas log masuk

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?)
Salin selepas log masuk

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!

sumber:stackoverflow.com
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan