【问题标题】:What's the purpose of deferred callbacks in libevent?libevent中延迟回调的目的是什么?
【发布时间】:2021-08-29 11:27:59
【问题描述】:

根据the libevent book

延迟回调

默认情况下,bufferevent 回调会在 相应的情况发生。 (这对于 evbuffer 回调是正确的 也;我们稍后会谈到这些。)这种立即调用可以使 当依赖关系变得复杂时会遇到麻烦。例如,假设有 是一个回调,当数据变空时将数据移动到 evbuffer A 中,并且 另一个在 evbuffer A 增长时处理数据的回调 满的。 由于这些调用都发生在堆栈上,您可能会冒险 如果依赖关系变得足够糟糕,则会发生堆栈溢出。

要解决这个问题,您可以告诉 bufferevent(或 evbuffer)它的 回调应该被推迟。当满足条件时 延迟回调,而不是立即调用它,而是排队 作为 event_loop() 调用的一部分,在常规调用之后调用 事件的回调。

如上所述:

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

提供了两个回调cacb。首先调用caca发现evbuffer_A为空,然后往里面写入消息。

然后,cb 被调用,cb 发现 evbuffer_A 包含一条消息,然后取出并发送出去。

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

所以,我的问题是:

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

【问题讨论】:

  • 发布的文字中解释了目的...您能否更具体地说明您的问题

标签: c linux networking network-programming libevent


【解决方案1】:

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

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

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-statements,但请记住事件系统与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 ...
}

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

延迟回调可以通过让一个回调在调用下一个回调之前完成来解决问题。

【讨论】:

  • 我还是一头雾水:因为调用FillBufferReadBuffer是一个无限循环,即使他们两个或一个被放入延迟队列,问题仍然存在。跨度>
  • @xmllmx 通过对ReadBuffer 使用延迟回调,然后FillBuffer 将在调用ReadBuffer 之前完成(反之亦然) .通过对ReadBuffer 使用“立即”回调,然后FillBuffer 将不会在调用ReadBuffer 之前完成(反之亦然)。这就是区别。
  • @xmllmx 不在我的伪代码中,而是在真实代码中(即没有 if 语句)然后是的,它将完成 .在类似main 的情况下,您可以交替调用FillBufferReadBuffer。这就是(或多或少)一个偶数驱动的系统延迟回调会做的事情。
  • @xmllmx 好吧,我不能比这更好地解释它了。不同之处在于触发回调的执行时间。 a) 立即(如中断)或 b) 延迟(如稍后)。您还可以使用以下术语:同步或异步。
  • @xmllmx 你的引号也这样写: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.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-29
  • 2021-03-27
  • 2012-09-30
  • 2016-07-27
  • 1970-01-01
  • 2011-01-12
相关资源
最近更新 更多