异步回调

发布于 2024-12-09 03:28:23 字数 905 浏览 0 评论 0原文

我是异步编程的新手。我有一个带有异步方法的 C# dll,该方法被调用,采用函数指针(委托)并在计算“结果”后调用此回调函数。

public delegate void CreatedDelegate(Foo result);

public void CreateAsync(CreatedDelegate createdCallback)
    {
        Task t = Task.Factory.StartNew(() =>
                                       {
                                        Foo result = ...
                                        createdCallback(result);
                                       });
    }

“CreatedDelegate”类型的委托回调(在我的例子中)是一个指向处理结果的 C++/CLI 方法的函数指针。

void CreatedCallback(Foo^ result)
{
    // do something with result
}

所以这个异步概念在大多数情况下似乎工作得很好,但有时我会遇到一些错误。如果使用不同的计算工作多次调用函数“CreateAsync”,导致对“CreatedCallback”的调用以与最初调用“CreateAsync”相同的顺序发生,我该如何实现呢?更清楚地说:第一次调用“CreateAsync”应该导致第一次调用“CreatedCallback”,即使后续调用“CreateAsync”速度更快并且实际上会更早调用回调。

也许这可以通过在异步“CreateAsync”中一次只允许一个活动的新线程来完成?

I am new to asynchronous programming. I have a C# dll with an asynchronous method that gets called, takes a function pointer (delegate) and calls this callback function after "result" is calculated.

public delegate void CreatedDelegate(Foo result);

public void CreateAsync(CreatedDelegate createdCallback)
    {
        Task t = Task.Factory.StartNew(() =>
                                       {
                                        Foo result = ...
                                        createdCallback(result);
                                       });
    }

The delegate callback of type "CreatedDelegate" is (in my case) a function pointer to a C++/CLI method that works with the result.

void CreatedCallback(Foo^ result)
{
    // do something with result
}

So this asynchronous concept seems to work quite well in most cases, but sometimes I encounter some errors. How can I achieve it if the function "CreateAsync" is called multiple times with different computation effort, that the resulting calls to "CreatedCallback" just happen in the same order as originally "CreateAsync" was called? To make it clearer: The first call to "CreateAsync" should result in the first call to "CreatedCallback" even if a succeeding call of "CreateAsync" is faster and would actually call the callback earlier.

Maybe this can be done by allowing only one active new thread in the asynchronous "CreateAsync" at a time?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

羁拥 2024-12-16 03:28:23

要按顺序处理回调,您需要实现一些工作项排队。最简单的方法可能是使用 BlockingCollection 类型(请参阅 MSDN文档)。

您的 CreateAsync 方法会将任务(与回调一起)添加到队列中,而不是调用回调:

// Queue to keep tasks and their callbacks
private BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>> 
  queue = new BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>()

public void CreateAsync(CreatedDelegate createdCallback) {
    Task<Foo> t = Task.Factory.StartNew(() =>  { 
      Foo result = ... 
      return result; });
    queue.Add(Tuple.Create(t, createdCallback));
    // ..
}

这只会将任务和回调添加到队列中 - 要实际调用回调,您将需要另一个任务来等待队列中的任务(按照添加顺序)并调用回调:

Task.Factory.StartNew(() => { 
  while(true) { // while you keep calling 'CreateAsync'
    // Get next task (in order) and its callback
    Tuple<Task<Foo>, CreatedDelegate> op = queue.Take();
    // Wait for the result and give it to callback
    op.Item2(op.Item1.Result);
  }
}

To process the callbacks in order, you'll need to implement some queueing of work items. The easiest way is probably to use BlockingCollection type (see MSDN documentation).

Instead of calling the callback, your CreateAsync method would add the task (together with the callback) to the queue:

// Queue to keep tasks and their callbacks
private BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>> 
  queue = new BlockingCollection<Tuple<Task<Foo>, CreatedDelegate>>()

public void CreateAsync(CreatedDelegate createdCallback) {
    Task<Foo> t = Task.Factory.StartNew(() =>  { 
      Foo result = ... 
      return result; });
    queue.Add(Tuple.Create(t, createdCallback));
    // ..
}

This will only add tasks and callbacks to the queue - to actually call the callback, you'll need another task that waits for the tasks in the queue (in the order in which they were added) and calls the callback:

Task.Factory.StartNew(() => { 
  while(true) { // while you keep calling 'CreateAsync'
    // Get next task (in order) and its callback
    Tuple<Task<Foo>, CreatedDelegate> op = queue.Take();
    // Wait for the result and give it to callback
    op.Item2(op.Item1.Result);
  }
}
森林散布 2024-12-16 03:28:23

如果顺序很重要,那么使用线程可能会更好:

thread queue = empty
for each task
{
  if there are no free 'cpu'
    wait on first thread in queue
    remove thread from queue
    call delegate

  create thread
  add thread to queue
}

while queue has threads
  wait on first thread in queue
  remove thread from queue
  call delegate

If order is important, then using Threads might be better:

thread queue = empty
for each task
{
  if there are no free 'cpu'
    wait on first thread in queue
    remove thread from queue
    call delegate

  create thread
  add thread to queue
}

while queue has threads
  wait on first thread in queue
  remove thread from queue
  call delegate
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文