我在C ++类中有几个成员函数,我将它们打包为dll 并尝试在C#应用程序中使用它们 我试图通过简单地使用线程执行它们然后分离它们来创建两个异步函数(),这样它们就不会阻塞调用者线程直到它们结束。 在基于C ++的应用程序中,每当我使用线程以这种方式调用函数时,它们都可以工作,但是当我尝试从c#调用我的异步函数时,我的应用程序崩溃或挂起!! 这些是我所谓的异步函数!:
void xGramManipulator::CreateMonoGramAsync()
{
thread t(&xGramManipulator::ReadMonoGram, this);
t.detach();
}
void xGramManipulator::CreateBiGramAsync()
{
thread t = thread(&xGramManipulator::ReadBiGram, this);
t.detach();
}
这是c中的包装函数,它位于一个dll中:
//header
CDLL_API void CreateMonoGramAsync(void);
//cpp
CDLL_API void CreateMonoGramAsync(void)
{
xG.CreateMonoGramAsync();
}
这是调用该函数的c#应用程序:
private void btnTest_Click(object sender, EventArgs e)
{
try
{
CreateBiGramAsync();
CreateMonoGramAsync();
}
catch (Exception)
{
}
}
如何在班上拥有真正的异步和非阻塞成员函数? 我在这里失踪了什么?
答案 0 :(得分:2)
我的猜测是,在将这些约定导入C#时,您没有指定调用约定 - 默认情况下,C#将使用stdcall
,而C ++将导出为cdecl
。你必须:
[DllImport("CDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void CreateMonoGramAsync();
或者,当您在C ++中声明方法时,您当然可以指定returntype __stdcall
。我也假设你已经正确宣布了这个功能(用extern "C" __declspec(dllexport)
等)。
答案 1 :(得分:0)
如果您使用的是.NET 4.5,则可以使用Task类来实现异步方法调用。
考虑以下示例:
static void Foo()
{
Thread.Sleep(2000);
Console.WriteLine("Foo called asynchronously!");
}
static void Main(string[] args)
{
var bar = Task.Factory.StartNew(() => { Foo(); });
Console.WriteLine("Called synchronously!");
Console.ReadLine();
}
每当执行此代码时,将启动对Foo()
的异步调用,等待两秒钟,然后将Foo called asynchronously!
写入控制台。另一个Console.WriteLine
调用是同步的,并且在异步调用开始后立即运行。
输出结果为:
Called synchronously!
Foo called asynchronously!
由于呼叫Foo()
未阻止呼叫者的线程。
您可以对代码执行相同操作,甚至可以删除方法中当前具有的线程以使它们异步。原因是即使他们创建自己的线程,.NET运行时仍然会等待这些函数返回。你最好这样称呼它们:
Task.Factory.StartNew(CreateBiGramAsync());
这样它们实际上将从.NET本身异步调用,并且它们不会阻止调用者线程。