Вызов обратного вызова Go из потокового низкоуровневого уровня кода C / C ++ в приложении Go - PullRequest
0 голосов
/ 12 февраля 2020

У меня есть приложение Go и некоторые функции API C (например, некоторые функции API Win32), которые работают асинхронно и порождают рабочие потоки. Эта функция API вызывает обратные вызовы от некоторых из этих рабочих потоков. Потоки являются системными и создаются внутри с помощью кода C (а не Go). Теперь я хочу передать функции Go в качестве обратных вызовов этой функции API C. Таким образом, функции обратного вызова Go будут вызываться функцией C в контексте рабочих потоков, неизвестных приложению Go.

Можно предположить, что были приняты меры безопасности и весь доступ к данным в обратных вызовах должным образом защищен мьютексами, чтобы не мешать основному Go коду.

Вопрос в том, «поддерживает ли Go такой сценарий?», То есть, будут ли обратные вызовы работать правильно, или что-то может легко взломать sh внутри, потому что среда выполнения Go не предназначена для того, что я хотел бы делать?

1 Ответ

0 голосов
/ 22 февраля 2020

Я провел эксперимент по созданию обратного вызова Go, вызванного из 20 собственных потоков Windows параллельно. Обратный вызов увеличивает переменную, добавляет элементы на карту и печатает значение на экране. Все работает гладко, поэтому я предполагаю, что не будет проблем и в более сложных сценариях ios.

Вот исходный код моих тестов для использования другими:

proxy.h

#ifndef _PROXY_H_
#define _PROXY_H_
long threaded_c_func(long param);
#endif

прокси. c

#include "proxy.h"
#ifdef WIN32
#include <Windows.h>
#endif

#define ROUNDS 20

volatile long passed = 0;

extern long long threadedCallback(long cbidx);

DWORD WINAPI ThreadFunc(LPVOID param) {    
    threadedCallback(*((long *)param));
    InterlockedIncrement(&passed);
}

long threaded_c_func(long cbidx) {

    for (int i  = 0; i < ROUNDS; i++)
    {
        DWORD ThreadId = 0;
        CreateThread(NULL, 1024*1024, &ThreadFunc, (LPVOID) &cbidx, 0, &ThreadId);
    }
    while (passed < ROUNDS)
    {
        Sleep(100);
    }
    return ROUNDS;
} 

callbackTest. go

package main

/*
#cgo CFLAGS: -I .
#cgo LDFLAGS: -L .

#include "proxy.h"

long threaded_c_func(long param);
*/
import "C"

import (
    "fmt"
    "strconv"
    "sync"
)

var hashTable map[int32]string

var count int32
var mtx sync.Mutex

//export threadedCallback
func threadedCallback(cbidx int) C.longlong {
    mtx.Lock()
    defer mtx.Unlock()
    count++
    hashTable[count] = strconv.Itoa(int(count))
    fmt.Println("Current counter ", count)
    return C.longlong(count)
}

func main() {
    hashTable = make(map[int32]string)
    var expected C.long
    expected = C.threaded_c_func(1)
    if int32(expected) == count {
        fmt.Println("Counters match")
    } else {
        fmt.Println("Expected ", int32(expected), " got ", count)
    }
    for k, v := range hashTable {
        if strconv.Itoa(int(k)) == v {
            fmt.Println(v, " match")
        } else {
            fmt.Println(v, "don't  match")
        }
    }
}
...