apache / brpc

brpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".
https://brpc.apache.org
Apache License 2.0
16.56k stars 3.98k forks source link

关于 StreamInputHandler 的析构时机 #2812

Closed yiliangyl closed 1 day ago

yiliangyl commented 2 weeks ago

在使用 stream rpc 时,发现会 coredump 在 Stream::Cosume 方法里 s->_options.handler->on_closed(s->id()); 这一行:

int Stream::Consume(void *meta, bthread::TaskIterator<butil::IOBuf*>& iter) {
    Stream* s = (Stream*)meta;
    s->StopIdleTimer();
    if (iter.is_queue_stopped()) {
        // ...
        if (s->_options.handler != NULL) {
            // ...
            s->_options.handler->on_closed(s->id());

然后看到 StreamOptions 里 StreamInputHandler(下面简写为 handler)是通过普通指针传入:

struct StreamOptions {
    // ...

    // Handle input message, if handler is NULL, the remote side is not allowed to
    // write any message, who will get EBADF on writting
    // default: NULL
    StreamInputHandler* handler;
};

同时在 Stream::Create 方法里直接通过拷贝的方式拿到 options:

int StreamCreate(StreamIds& request_streams, int request_stream_size, Controller & cntl,
                 const StreamOptions* options) {
    // ...
    StreamOptions opt;
    if (options != NULL) {
        opt = *options;
    }

随之让消息通过 Stream::Consume 方法异步消费。

在个人代码中,使用了智能指针来析构 handler。从结果来看,由于指针拷贝,s->_options.handler 并不会为 NULL,但 handler 实际上已经析构了,如果仍执行 Stream::Consume 方法,则导致 coredump。看了一圈似乎没有接管 handler 生命周期的方法,也没有告知能安全析构 handler 的方法。所以请问下,什么时候析构 handler 才是安全的?还是说我的使用姿势有问题?感谢解答

chenBright commented 2 weeks ago

没法安全析构handler,将handler看做是单例吧,不用析构。