libevent 中延迟回调的目的是什么?

What's the purpose of deferred callbacks in libevent?

根据the libevent book

Deferred callbacks

By default, a bufferevent callbacks are executed immediately when the corresponding condition happens. (This is true of evbuffer callbacks too; we’ll get to those later.) This immediate invocation can make trouble when dependencies get complex. For example, suppose that there is a callback that moves data into evbuffer A when it grows empty, and another callback that processes data out of evbuffer A when it grows full. Since these calls are all happening on the stack, you might risk a stack overflow if the dependency grows nasty enough.

To solve this, you can tell a bufferevent (or an evbuffer) that its callbacks should be deferred. When the conditions are met for a deferred callback, rather than invoking it immediately, it is queued as part of the event_loop() call, and invoked after the regular events' callbacks.

如上所述:

  1. 事件循环获取一批事件,并立即一个一个地处理它们。
  2. 在处理提取的事件之前,不会提取和处理任何新事件。
  3. 如果一个事件被标记为 BEV_OPT_DEFER_CALLBACKS,则将在处理完同一批次中的所有其他事件后处理该事件。

提供了两个回调 cacb。首先调用caca发现evbuffer_A为空,然后向其中写入一条消息。

然后调用cbcb发现evbuffer_A有一条消息,然后抓取并发送出去。

调用cb时,ca的堆栈已经释放。我认为在这种情况下不会出现堆栈溢出。

那么,我的问题是:

libevent 中延迟回调的目的是什么?

引用文本中给出的示例是缓冲区在一个事件后被填充并在另一个事件后清空。

考虑这个非事件驱动的伪代码,用于同一示例。

void FillBuffer(...)
{
    while (BufferNotFull)
    {
        PutDataInBuffer(...);
    }
    If (BufferIsFull)  // emulates buffer-full event
    {
        ReadBuffer(...);
    }

    ... more code ...
}

void ReadBuffer(...)
{
    while (BufferNotEmpty)
    {
        ReadDataFromBuffer(...);
    }
    If (BufferIsEmpty)  // emulates buffer-empty event
    {
        FillBuffer(...);
    }

    ... more code ...
}

显然,两个if语句的条件总是为真。因此,这些功能永远不会完成,而是不断地相互调用。堆栈迟早会溢出。

现在想象一个事件驱动系统,其中所有 回调在事件触发后立即发生 (即删除 if 语句,但请记住事件系统确实与 if 语句相同)。喜欢:

void FillBuffer(...)  // Called on buffer-empty event
{
    while (BufferNotFull)
    {
        PutDataInBuffer(...);
    }
    // Event buffer-full triggered (i.e. ReadBuffer being called)

    ... more code ...
}

void ReadBuffer(...)  // Called on buffer-full event
{
    while (BufferNotEmpty)
    {
        ReadDataFromBuffer(...);
    }
    // Event buffer-empty triggered (i.e. FillBuffer being called)

    ... more code ...
}

这样的系统将执行与非事件驱动伪代码相同的操作,即在第一个回调完成之前调用下一个回调。

延迟回调可以解决问题,方法是让一个回调在调用下一个回调之前完成。