asyncio icon indicating copy to clipboard operation
asyncio copied to clipboard

对 Stream::write() 的一点解惑

Open microcai opened this issue 1 year ago • 0 comments

作者在代码里写了这么一个 FIXME

    Task<> write(const Buffer& buf) {
        auto& loop = get_event_loop();
        ssize_t total_write = 0;
        while (total_write < buf.size()) {
            // FIXME: how to handle write event?
            // co_await write_awaiter_;
            ssize_t sz = ::write(write_fd_, buf.data() + total_write, buf.size() - total_write);
            if (sz == -1) {
                throw std::system_error(std::make_error_code(static_cast<std::errc>(errno)));
            }
            total_write += sz;
        }
        co_return;
    }

并且注释掉了 co_await write_awaiter_; 因此,写操作是个同步操作。一旦把内核的写缓冲区写满,就要返回失败了。

那么问题来了,为啥要注释掉呢???

我猜测作者在这里遇到了无法解决的崩溃问题。

原因其实在于,这里调用的 co_await write_awaiter_,write_awaiter_ 不是一个右值对象。 因此,注册了 写事件的等待后,没有解注册。。。。。反而会不断的重复注册监控写事件。。。。

解决办法有两个: 其一是 epoll_ctl 添加事件使用 ONE_SHOT 标志。确保内核只通知一次。这样事件就不需要再次调用 epoll_ctl 清除了。 其二是每次这里都创建一个临时的 WaitEventAwaiter 对象。等待完毕,就可以利用 WaitEventAwaiter 自动调用 selector_.remove_event

任选其一崩溃自解。

microcai avatar Nov 23 '24 15:11 microcai