2017-04-08 3 views
1

Ich schreibe ein Paket zur Steuerung einer Canon DSLR mit ihrer EDSDK DLL von Go.Aufruf von Funktionen in einer "LockOSThread" GoRoutine

Dies ist ein persönliches Projekt für eine Fotokabine zu unserer Hochzeit bei meiner Partner Anfrage, die ich gerne auf GitHub veröffentlichen werde, wenn abgeschlossen :).

Wenn Sie sich die Beispiele für die Verwendung des SDK an anderer Stelle ansehen, ist es kein threadsicheres Werkzeug und verwendet thread-lokale Ressourcen. Daher muss ich sicherstellen, dass ich es während der Verwendung aus einem einzigen Thread heraus aufruft. Obwohl es nicht ideal ist, sieht es so aus, als ob Go eine "runtime.LockOSThread" -Funktion bereitstellt, obwohl das vom internen DLL-Interop-Code selbst aufgerufen wird, also muss ich warten und herausfinden, ob das stört oder nicht.

Ich möchte den Rest der Anwendung in der Lage sein, das SDK über eine höhere Ebene Schnittstelle ohne sich über die Threading zu kümmern, so brauche ich eine Möglichkeit, Funktionsaufruf an den gesperrten Thread/Goroutine übergeben, um dort auszuführen Übergeben Sie die Ergebnisse an die aufrufende Funktion außerhalb dieser Goroutine zurück.

Bisher habe ich dieses Arbeitsbeispiel für die Verwendung sehr breiter Funktionsdefinitionen unter Verwendung von [] Interface {} - Arrays und für die Vor- und Zurückübertragung über Kanäle entwickelt. Dies würde bei jedem Aufruf eine Menge an Eingabe-/Ausgabedaten erfordern, um Assertions wieder aus dem Array der Schnittstelle {} herauszulösen, selbst wenn wir wissen, was wir für jede Funktion im voraus erwarten sollten, aber es sieht so aus Arbeit.

Bevor ich viel Zeit auf diese Weise für möglicherweise den schlechtesten Weg zu tun investieren - hat jemand bessere Möglichkeiten?

package edsdk 

import (
    "fmt" 
    "runtime" 
) 

type CanonSDK struct { 
    FChan   chan functionCall 
} 

type functionCall struct { 
    Function  func([]interface{}) []interface{} 
    Arguments  []interface{} 
    Return   chan []interface{} 
} 

func NewCanonSDK() (*CanonSDK, error) { 
    c := &CanonSDK { 
     FChan: make(chan functionCall), 
    } 

    go c.BackgroundThread(c.FChan) 

    return c, nil 
} 

func (c *CanonSDK) BackgroundThread(fcalls <-chan functionCall) { 
    runtime.LockOSThread() 
    for f := range fcalls { 
     f.Return <- f.Function(f.Arguments) 
    } 
    runtime.UnlockOSThread() 
} 

func (c *CanonSDK) TestCall() { 
    ret := make(chan []interface{}) 

    f := functionCall { 
     Function: c.DoTestCall, 
     Arguments: []interface{}{}, 
     Return: ret, 
    } 

    c.FChan <- f 

    results := <- ret 
    close(ret) 

    fmt.Printf("%#v", results) 
} 

func (c *CanonSDK) DoTestCall([]interface{}) []interface{} { 
    return []interface{}{ "Test", nil } 
} 
+0

Ihre Frage könnte für SO zu komplex sein. Versuchen Sie, es auf eine einzige Sorge in Code herunterzukochen. – eduncan911

Antwort

0

Für ähnliche eingebettete Projekte, die ich mit gespielt habe, neige ich dazu, einen einzigen goroutine Arbeiter zu schaffen, die auf einem Kanal hört die ganze Arbeit über dieses USB-Gerät auszuführen. Und alle Ergebnisse werden auf einem anderen Kanal gesendet.

Sprechen Sie das Gerät mit Kanälen nur in Go in einem Einwegaustausch. LIstin für Antworten vom anderen Kanal.

Da USB seriell und polling ist, musste ich einen dedizierten Kanal mit einer anderen Goroutine einrichten, die gerade Elemente aus dem Kanal auswählt, wenn sie von der Worker-Routine, die gerade geloopt wurde, hineingeschoben wurden.

Verwandte Themen