Multithreading 从线程化低级C/C+;调用Go回调+;Go应用程序中的代码层

Multithreading 从线程化低级C/C+;调用Go回调+;Go应用程序中的代码层,multithreading,go,c-api,Multithreading,Go,C Api,我有一个Go应用程序和一些C API函数(例如一些Win32 API函数),它们异步工作并生成工作线程。此API函数调用来自某些工作线程的回调。线程是系统线程,由C代码(而不是Go)在内部创建。现在,我想将Go函数作为回调传递给该C API函数。因此,Go回调函数将由C函数在工作线程的上下文中调用,Go应用程序不知道 我们可以假设已经采取了安全措施,并且回调中的所有数据访问都由互斥体进行了适当的保护,以避免干扰主Go代码 问题是“Go是否支持这样的场景?”,即回调是否正常工作,或者由于Go运行时

我有一个Go应用程序和一些C API函数(例如一些Win32 API函数),它们异步工作并生成工作线程。此API函数调用来自某些工作线程的回调。线程是系统线程,由C代码(而不是Go)在内部创建。现在,我想将Go函数作为回调传递给该C API函数。因此,Go回调函数将由C函数在工作线程的上下文中调用,Go应用程序不知道

我们可以假设已经采取了安全措施,并且回调中的所有数据访问都由互斥体进行了适当的保护,以避免干扰主Go代码


问题是“Go是否支持这样的场景?”,即回调是否正常工作,或者由于Go运行时不是为我想做的事情而设计的,因此内部很容易崩溃

我做了一个Go回调的实验,从20个本地Windows线程并行调用。回调增加一个变量,向映射中添加元素,并在屏幕上打印值。一切都很顺利,所以我假设在更复杂的场景中也不会出现问题

以下是我测试的源代码,供其他人使用:

代理

代理c


如果您能够共享示例代码,则可能对其他人有益:)
#ifndef _PROXY_H_
#define _PROXY_H_
long threaded_c_func(long param);
#endif
#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;
} 
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")
        }
    }
}