Maison > développement back-end > Golang > le corps du texte

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

PHPz
Libérer: 2024-02-12 17:51:05
avant
570 Les gens l'ont consulté

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>
Copier après la connexion

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>
Copier après la connexion

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?)
Copier après la connexion

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!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal