1

我正在编写一个包来使用来自 Go 的 EDSDK DLL 来控制佳能 DSLR。

这是我的合作伙伴要求在我们的婚礼上使用的照相亭的个人项目,我很乐意在完成后将其发布在 GitHub 上:)。

查看在其他地方使用 SDK 的示例,它不是线程安全的并且使用线程本地资源,因此我需要确保在使用期间从单个线程调用它。虽然并不理想,但看起来 Go 提供了一个“runtime.LockOSThread”函数来执行此操作,尽管它确实被核心 DLL 互操作代码本身调用,所以我必须等待并找出是否会干扰。

我希望应用程序的其余部分能够使用更高级别的接口调用 SDK 而不必担心线程,所以我需要一种方法将函数调用请求传递给锁定的线程/Goroutine 以在那里执行,然后将结果传回到该 Goroutine 之外的调用函数。

到目前为止,我已经提出了这个使用非常广泛的函数定义的工作示例,它使用 []interface{} 数组并通过通道来回传递。这将需要在每次调用时对输入/输出数据进行大量修改,以便从 interface{} 数组中返回类型断言,即使我们提前知道每个函数应该期待什么,但看起来它会工作。

在我投入大量时间以可能是最糟糕的方式这样做之前 - 有人有更好的选择吗?

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

1 回答 1

0

对于我玩过的类似嵌入式项目,我倾向于创建一个 goroutine 工作程序,它在一个通道上侦听以通过该 USB 设备执行所有工作。并将任何结果发送回另一个频道。

以单向交换方式与仅在 Go 中使用频道的设备对话。聆听来自其他频道的响应。

由于 USB 是串行和轮询的,因此我必须使用另一个 goroutine 设置一个专用通道,当它们从刚刚循环的工作 goroutine 推入通道时,它会从通道中挑选项目。

于 2017-04-08T12:46:11.137 回答