知道所有回调都使用 libevent 和 bufferevent_free 运行

Posted

技术标签:

【中文标题】知道所有回调都使用 libevent 和 bufferevent_free 运行【英文标题】:Knowing all callbacks have run with libevent and bufferevent_free 【发布时间】:2015-07-28 23:15:23 【问题描述】:

我正在使用 2.0.22 版的 libevent 进行一些工作,并且正在努力处理 bufferevent_free 并确保套接字在正确的时间关闭。这是使用 Xcode 6.4 构建的 ios 应用程序,在 iOS 8.4 上运行。

每个套接字都由struct bufferevent 管理,我还有一个数据结构来跟踪该套接字的应用程序状态:

bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_socket_connect_hostname(bev, dns_base, AF_UNSPEC, host, port_number);
struct stream_data *data = malloc(sizeof(struct stream_data));
/* initialize stream data here */
bufferevent_setcb(bev, read_cb, write_cb, event_cb, data);

在来自其他缓冲区套接字的回调中,我决定不需要我刚刚尝试打开的缓冲区。这发生在之前,我在有问题的 bev 上获得了连接的回调。因为我是用BEV_OPT_CLOSE_ON_FREE 创建的,所以我把它释放了。然后我删除我正在使用的数据结构。看起来像这样:

bufferevent_free(bev);
free(stream_data); // the data corresponding to that bev

不过,在这种情况下,套接字实际上同时完成了连接。所以我的事件回调触发:

void event_cb(struct bufferevent *bev, short what, void *ctx)

    struct stream_data *data = ctx;
    // data now points to already freed memory

现在我有一个指向已释放内存的指针。我已通过调试器断点、NSLog 等确认事件回调在上述free 之后触发。

这是预期的行为吗?如果是这样,我怎么知道我释放的缓冲区事件已经完全消失了,从而可以安全地删除我自己的数据结构?

【问题讨论】:

这听起来很奇怪,bufferevent_free 禁用所有事件并在事件被释放之前取消所有未决事件。还有其他事情吗(例如,这是多线程代码吗?以及您使用的是哪个 libevent 版本?) 这是多线程代码,但我已经验证这些对 libevent 的调用仅发生在事件循环线程上的回调中。我将在问题中添加更多细节。 编辑了更多细节。也可以使用 libevent 2.1.5-beta 获得相同的行为 【参考方案1】:

是的,这是预期的 libevent 行为:在 bufferevent_free() 之后它仍然可能调用您的回调。来自 libevent 书:

Bufferevents 是内部引用计数的,所以如果 bufferevent 在你释放它时有挂起的延迟回调,在回调完成之前它不会被删除。

最简单的解决方案是在释放 bufferevent 对象之前移除所有回调:

bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
bufferevent_free(bev);

【讨论】:

我也不得不调用 evtimer_del() 但遗憾的是在调用 bufferevent_free(bev); 后仍然得到超时回调;更重要的是,在调用 event_base_free(base); 之后...所以我仍然得到一个 SIGSEVF @CodeAbominator 窃取 evtimer_del() 尝试 event_del()。

以上是关于知道所有回调都使用 libevent 和 bufferevent_free 运行的主要内容,如果未能解决你的问题,请参考以下文章

Libevent

libevent:从缓冲区读取所有字节

如何使用 Libevent 检测客户端连接到服务器

使用 libevent 在 C 中的 TCP 端口事件回调

libevent源码分析-介绍安装使用

EventFD 可以与 libEvent2 一起使用吗?