في Go 1.6 والإصدارات الأحدث، لدى Cgo قواعد أكثر صرامة للتمرير مؤشرات إلى رمز C. لم يعد مسموحًا بتمرير مؤشر Go الذي يشير إلى ذاكرة Go التي تحتوي على أي مؤشرات Go.
يوضح كود Go التالي كيفية تمرير مؤشر دالة إلى كود C:
import (
"fmt"
"unsafe"
)
/*
extern void go_callback_int(void* foo, int p1);
static inline void CallMyFunction(void* pfoo) {
go_callback_int(pfoo, 5);
}
*/
import "C"
//export go_callback_int
func go_callback_int(pfoo unsafe.Pointer, p1 C.int) {
foo := *(*func(C.int))(pfoo)
foo(p1)
}
func MyCallback(x C.int) {
fmt.Println("callback with", x)
}
// we store it in a global variable so that the garbage collector
// doesn't clean up the memory for any temporary variables created.
var MyCallbackFunc = MyCallback
func Example() {
C.CallMyFunction(unsafe.Pointer(&MyCallbackFunc))
}
func main() {
Example()
}
عند تشغيل هذا الرمز، ينتج خطأ لأن ذاكرة Go المشار إليها بواسطة MyCallbackFunc تحتوي على مؤشر وظيفة Go (MyCallback).
للعنوان هذا، نحتاج إلى إيجاد طريقة لتمرير مؤشر الوظيفة إلى كود C دون انتهاك القواعد الجديدة.
استخدام معرف بدلاً من المؤشر
تتمثل إحدى الطرق في تخزين مؤشر الوظيفة في بنية بيانات متزامنة وتمرير معرف إلى كود C بدلاً من المؤشر المباشر. بهذه الطريقة، يمكن لرمز C استخدام المعرف للوصول إلى مؤشر الوظيفة من خلال بنية البيانات.
الحزمة مع تمرير مؤشر الوظيفة المستند إلى المعرف
package gocallback
import (
"fmt"
"sync"
)
/*
extern void go_callback_int(int foo, int p1);
static inline void CallMyFunction(int foo) {
go_callback_int(foo, 5);
}
*/
import "C"
//export go_callback_int
func go_callback_int(foo C.int, p1 C.int) {
fn := lookup(int(foo))
fn(p1)
}
func MyCallback(x C.int) {
fmt.Println("callback with", x)
}
func Example() {
i := register(MyCallback)
C.CallMyFunction(C.int(i))
unregister(i)
}
var mu sync.Mutex
var index int
var fns = make(map[int]func(C.int))
func register(fn func(C.int)) int {
mu.Lock()
defer mu.Unlock()
index
for fns[index] != nil {
index
}
fns[index] = fn
return index
}
func lookup(i int) func(C.int) {
mu.Lock()
defer mu.Unlock()
return fns[i]
}
func unregister(i int) {
mu.Lock()
defer mu.Unlock()
delete(fns, i)
}
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3