为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
慕后森 2022-05-18 09:51:32
我有一个 Go 应用程序和一些 C API 函数(例如一些 Win32 API 函数),它们异步工作并产生工作线程。此 API 函数从其中一些工作线程调用回调。线程是系统线程,由 C 代码(而不是 Go)在内部创建。现在,我想将 Go 函数作为回调传递给该 C API 函数。因此,Go 回调函数将由 C 函数在工作线程的上下文中调用,Go 应用程序不知道。我们可以假设已经采取了安全措施,并且回调中的所有数据访问都由互斥锁适当地保护,以免干扰主 Go 代码。问题是“Go 是否支持这种情况?”,即回调会正常工作还是因为 Go 运行时不是为我想做的事情而设计的东西很容易在内部崩溃?
查看完整描述

1 回答

?
BIG阳

TA贡献1859条经验 获得超6个赞

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


这是我的测试的源代码供其他人使用:


代理.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;

回调Test.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")

        }

    }

}


查看完整回答
反对 回复 2022-05-18
  • 1 回答
  • 0 关注
  • 108 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信