Вызов функций внутри GoRoutine "LockOSThread"
Я пишу пакет для управления зеркальной фотокамерой Canon с помощью их библиотеки EDSDK от Go.
Это персональный проект для фотобудки, который будет использоваться на нашей свадьбе по запросу моих партнеров, и я буду рад опубликовать его на 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 }
}
1 ответ
Для подобных встроенных проектов, с которыми я играл, я склонен создавать одного рабочего горутина, который прослушивает канал для выполнения всей работы над этим USB-устройством. И любые результаты отправляются обратно на другой канал.
Поговорите с устройством только с каналами в Go в одностороннем порядке. LIsten для ответов от другого канала.
Поскольку USB является последовательным и опрашивающим, мне пришлось настроить выделенный канал с другой последовательностью, которая просто выбирает элементы из канала, когда они вставляются в него из рабочей циклической программы, которая только что зациклилась.