Вызов функций внутри 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 является последовательным и опрашивающим, мне пришлось настроить выделенный канал с другой последовательностью, которая просто выбирает элементы из канала, когда они вставляются в него из рабочей циклической программы, которая только что зациклилась.

Другие вопросы по тегам