Maison  >  Article  >  développement back-end  >  Passer un tableau 2D de Go à C à l'aide de runtime.Pinner

Passer un tableau 2D de Go à C à l'aide de runtime.Pinner

PHPz
PHPzavant
2024-02-12 17:51:05571parcourir

Passer un tableau 2D de Go à C à laide de runtime.Pinner

Contenu de la question

J'essaie de transmettre un tableau 2D de Go à une fonction C void foo(in **float, out *double)。因为我想要这个 C 函数的包装器,所以我希望 Go 函数具有像 func FooWrapper([][]float32) []float64 définie comme ceci. L'implémentation la plus simple mais pas très efficace consiste à allouer toute la mémoire via C répertorié ci-dessous :

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

Cette mise en œuvre est-elle sûre ? Puis-je passer un pointeur vers les resultdata ? Autant que je sache, ce pointeur sera épinglé car il est passé à la fonction C.

Mais je veux allouer moins de mémoire et simplement réutiliser la mémoire Go, je connais déjà l'appel runtime.Pinner ,它使指针固定直到 runtime.Pinner.Unpin(). J'ai essayé d'écrire une autre implémentation en utilisant 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>

Mais malheureusement, ce code ne fonctionne pas

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

Est-ce que j'utilise mal runtime.Pinner (pour autant que je sache, je peux épingler des données de tranche) ? Ou il y a un autre bug dans ce code. Existe-t-il une implémentation permettant de transmettre un tableau 3D (4D, etc.) à une fonction C en plus d'allouer et de copier toutes les données dans la mémoire C ?

Solution

J'ai trouvé la réponse à mon problème. Utiliser malloc est dangereux car lorsque j'essaie d'écrire un pointeur Go sur la mémoire C, le GC peut reconnaître la mémoire non initialisée comme une "mauvaise" mémoire, donc si je change malloc en calloc, il n'y aura aucun problème. Bien sûr, ce n’est pas la meilleure solution, il est préférable d’allouer de la mémoire dans Go car c’est plus rapide et plus sûr.

Toutes les discussions ici一个>.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer