вызывая указатель обратного вызова Python с го - PullRequest
0 голосов
/ 26 мая 2018

Я получаю эту ошибку:

Ticker ticked
unexpected fault address 0xb01dfacedebac1e
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0xb01dfacedebac1e pc=0x105c4152e]

goroutine 17 [running, locked to thread]:
runtime.throw(0x105c74358, 0x5)
/usr/local/go/src/runtime/panic.go:616 +0x81 fp=0xc420050d48 sp=0xc420050d28 pc=0x105bd6951
runtime.sigpanic()
/usr/local/go/src/runtime/signal_unix.go:395 +0x211 fp=0xc420050d98 sp=0xc420050d48 pc=0x105beabf1
main.callme(0x105baefc0)
/Users/xxx/go/src/test2/test2.go:29 +0xce fp=0xc420050e90 sp=0xc420050d98 pc=0x105c4152e
main._cgoexpwrap_f53316e445a2_callme(0x105baefc0)
_cgo_gotypes.go:45 +0x2b fp=0xc420050ea8 sp=0xc420050e90 pc=0x105c4144b
runtime.call32(0x0, 0x7ffeea2482b0, 0x7ffeea248348, 0x8)
/usr/local/go/src/runtime/asm_amd64.s:573 +0x3b fp=0xc420050ed8 sp=0xc420050ea8 pc=0x105bfe7eb
runtime.cgocallbackg1(0x0)
/usr/local/go/src/runtime/cgocall.go:316 +0x19c fp=0xc420050f58 sp=0xc420050ed8 pc=0x105bb284c
runtime.cgocallbackg(0x0)
/usr/local/go/src/runtime/cgocall.go:194 +0xda fp=0xc420050fc0 sp=0xc420050f58 pc=0x105bb261a
 runtime.cgocallback_gofunc(0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/runtime/asm_amd64.s:826 +0x9b fp=0xc420050fe0 sp=0xc420050fc0 pc=0x105bffdbb
 runtime.goexit()
/usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc420050fe8 sp=0xc420050fe0 pc=0x105c00a31

Код перехода:

    package main
    import "time"
    import "fmt"
    import "C"

    type convert func()

    //export callme
    func callme(fn convert) {
        doneChan := make(chan bool)
go func() {
    time.Sleep(time.Second * 5)
    doneChan <- true
}()
ticker := time.NewTicker(time.Millisecond * 500)
for {
    select {
    case <- ticker.C:
        fmt.Println("Ticker ticked")
        fn()
    case <- doneChan:
        fmt.Println("Done")
        return
  }
}
}
func main() {
ticker := time.NewTicker(time.Millisecond * 1000)
time.Sleep(time.Millisecond * 1500)
ticker.Stop()
fmt.Println("Ticker stopped")
}

Код Python:

from ctypes import *
def print_tick():
   print("hey")
   return 0
lib = cdll.LoadLibrary("./test2.so")


CMPFUNC = CFUNCTYPE(c_int)
cmp_func = CMPFUNC(print_tick)

callme = lib.callme
callme(cmp_func)

Это был всего лишь тесткод, чтобы увидеть, как я могу использовать обратный вызов между Python и Go и, если это возможно.В идеале сторона Python запускает код go для запуска в фоновом режиме.Механизм go получает поток сообщений, и после получения сообщения механизм go вызывает функцию обратного вызова из python и передает эти сообщения в python.

Ответы [ 2 ]

0 голосов
/ 25 мая 2019

Проблема здесь в типе аргумента "callme".Код Python использует ctypes, чтобы дать ему указатель на функцию в стиле C.Ваш код Go получает его как функцию Go, которой он не является.

Сначала необходимо определить "callme" следующим образом:

func callme(fn C.convert)

Затем необходимо определить C.convert,Документация Go https://golang.org/cmd/cgo/ описывает, как вы можете добавить фрагмент кода C в исходный файл Go.

/*
typedef void (*convert) ();
*/
import "C"

Поскольку невозможно напрямую вызвать указатель на функцию, необходимо создатьФункция C, которая принимает указатель в качестве параметра и вызывает его.

/*
typedef void (*convert) ();

static inline void call_c_func(convert ptr) {
    (ptr)();
}
*/
import "C"

Теперь C.call_c_func можно использовать для вызова функции обратного вызова, полученной от python, заменив прямой вызов функции fn ().

//fn()
C.call_c_func(fn)
0 голосов
/ 26 мая 2018

Это не будет работать без использования C в качестве посредника при переходе обратно в python.

Указатель на функцию go не будет выглядеть так же, как указатель на функцию python.Код go падает, когда он ожидает увидеть fn как функцию go.Но это указатель на функцию Python.Сообщение о жирном шрифте смешно - они явно предвидели эту ошибку и используют 0xb01dfacedebac1e в качестве значения указателя.

Вы можете попробовать просто использовать возвращаемое значение callme в python.Когда приходит сообщение, верните его из callme, а затем снова вызовите callme из python для следующего сообщения.Возвращаемое значение в python должно быть чем-то, что python может понять.

В противном случае, если возможно вызвать из c в python, вы можете использовать функцию ac в качестве посредника и предоставить эту функцию c в качестве обратного вызова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...