我正在编写一个包来使用来自 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 }
}