asnychronous callback

本文关键字:callback asnychronous | 更新日期: 2023-09-27 18:11:01

我是异步编程新手。我有一个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"在一个时间?

asnychronous callback

要按顺序处理回调,您将需要实现一些工作项排队。最简单的方法可能是使用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);
  }
}

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

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