Зная, что все обратные вызовы выполняются с libevent и bufferevent free


Я делаю некоторую работу с libevent, версия 2.0.22, и я борюсь с тем, чтобы иметь дело с bufferevent_free и убедиться, что сокеты закрываются в нужное время. Это приложение для iOS, построенное на Xcode 6.4 и работающее на 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_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, который я освободил, действительно исчез, что делает безопасным удаление моих собственных структур данных?

1 3

1 ответ:

Да, это ожидаемое поведение libevent: после bufferevent_free() он все еще может вызывать ваши обратные вызовы. Из книги libevent:

Bufferevents внутренне подсчитываются по ссылкам, поэтому, если у bufferevent есть отложенные отложенные обратные вызовы, когда вы его освобождаете, он не будет удален, пока обратные вызовы не будут выполнены.

Самым простым решением является удаление всех обратных вызовов перед освобождением объекта bufferevent:

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