Coder Social home page Coder Social logo

下一个版本解决问题。 about uv-cpp HOT 21 CLOSED

wlgq2 avatar wlgq2 commented on August 23, 2024
下一个版本解决问题。

from uv-cpp.

Comments (21)

x724172556 avatar x724172556 commented on August 23, 2024 1

最近看了很多EventLoop库,包括muduo,其实打多数库存在的问题是回调陷阱,就是回调发生期间,所依赖的对象已经被销毁的情况,导致段错误等问题,muduo这个问题会更加严重,uv-cpp至少能够在close的回调中delete掉对象,,muduo大部分情况下不知道在什么时候去销毁对象,可能在你刚销毁后,就遇到了捆绑此对象的回调,导致段错误。。
我觉得一个好的方法是全面使用智能指针,使用shared_ptr阻止其在回调没有执行前不能销毁,或者使用weak_ptr判断对象如果已经销毁了就不执行回调。
另外就是使用qt或者sigc这种信号和槽的机制,关注对象的生命周期,如果绑定的对象被销毁了,那么他就不会再去执行对应的回调了
这可能是最影响各种库稳定性的问题,还是那个最基本的问题,析构函数并没有清理掉所有相关联的资源,包括其他对象对这个对象的依赖。

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

我尝试过,直接用runinthisloop,去执行async_->close,和uv_stop(handle),但是产生一个问题,eventloop中的async_的uv handle_是只能在之后的事件循环中被回调delete,像这样
::uv_close((uv_handle_t*)handle_, [](uv_handle_t* handle)
{
delete (uv_async_t*)handle;
});
但是loop在当前循环中已经被停止了,所以这个回调不能被调用,导致最终的内存泄漏,我觉得async 中的handle_的销毁应该交给async的析构,而不应当在事件回调中

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

类似signal也是一样,只能主动调用close,并且当前的eventloop是正常执行的。

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

@x724172556
在析构里面释放也会有问题。句柄必须在回调中释放。
所以这是我下一个版本要考虑的问题。
因为我自己使用Loop没有释放的需求,正常的程序里面也不会频繁创建Loop(想想只有动态扩展线程池才有这个需求)。
后面看看怎么弄比较安全,会解决这个问题。

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

我想到了一个方法,但没有尝试过,就是eventloop添加一个接口,close(callback),我们在callback回调中执行关闭其他句柄的操作,例如tcpserver,此时uv_loop是已经停止了,下一次是无法进入循环的,真正的关闭句柄操作是无法执行的,那么我们再启动一次uv_loop,这次试用uv_run(onces),这样他就只执行一次循环就退出了,这个方法是否可行

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

或者是在,callback执行以后,请求一个异步的关闭操作,在下个循环执行uv_stop

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

void EventLoop2::stop(StopCallback callback)
{

runInThisLoop([this,callback](){
    callback();
    async_->close(nullptr);

     uv_stop(handle());
});

}实际发现这样写,就能结束循环,并且能将 async_的uv句柄释放掉,只需要保证在uv_stop之前关闭掉其他句柄就可以了

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

计划10.1更。

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

v1.5.1 版本,增加eventloop退出机制,windows下测试无内存泄漏。例程:https://github.com/wlgq2/uv-cpp/tree/master/examples/loop_exit

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

增加server退出机制。

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

@x724172556 因为uv-cpp无法控制libuv不对一个析构对象的调用。接口最初设计成这样是为了向libuv妥协。后面看看有没有更好的办法。

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

将需要回调的对象(tcpclient)继承object,然后object会将自身注册进eventloop,析构的时候注销,回调的话,就可以判断对象的生命周期,存活就回调。。。这是传统c++面对对象的事件框架机制,我不知道你对这种方案是否认同

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

其实自己在对象外面包一层,析构里面Close,回调删对象,也不用手动调Close,直接删对象就行。参考HttpClient中删TcpClient。
https://github.com/wlgq2/uv-cpp/blob/master/uv/http/HttpClient.cpp
HttpClient::~HttpClient()
{
client_->close([](uv::TcpClient* client)
{
delete client;
});
}

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

@x724172556 问题是,回调是从libuv中触发,我无法把智能指针保存到libuv里面不被析构。还有一个问题,就算智能指针保证了C++的析构后的对象不被调用。但是不能维护libuv自己指针的生命周期,比如在libuv自己loop未结束时,智能指针删除了某个libuv的句柄。程序core。
如果你觉得可行,可以尝试提交个dome,或者pr试试。

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

给libuv的相关句柄在做一个 封装,这个封装不对外接口暴露,只是内部对象析构的调用这个句柄close,然后删句柄就行。有时间改改看。

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

对,我的其中一个想法就是,析构函数应该执行一次close,因为我不知道libuv的close设置为null还会不会依赖uv_handle,所以我让他在所有的libuv的回调中先判断对象是否存活

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

httpclient也是一个挺好的方法,把原来的tcpclient隐藏,作为一个内部类

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

唯一的问题可能就是,如果eventloop stop之后,再析构,可能会导致close回调不会调用,导致内存泄漏

from uv-cpp.

wlgq2 avatar wlgq2 commented on August 23, 2024

你看runInLoop实现,如果当前loop是被停止的,是直接在调用线程中运行回调的。如果是loop没开始,则等待开始后在loop中回调。

from uv-cpp.

x724172556 avatar x724172556 commented on August 23, 2024

那应该没有问题

from uv-cpp.

sjhgithub avatar sjhgithub commented on August 23, 2024

我的解决思路如下所述,不过实际代码感觉很烂,需要的话可以提交
解决死亡之吻(对象实例销毁后,如果之前提交了很多回调,会回调进入函数代码,由于对象已经销毁,将造成内存访问异常,发生崩溃)
主要步骤:
一是在上述实例(母体)中new一个that类(子体)(that对应this),并在子体中记录母体对象(body->this),在母体回调函数中根据该that对象,判断body(实体)是否已经销毁了,采取相应的动作
二是在母体中加上一个门卫(std::recursive_mutex),母体析构函数和回调函数通过该门卫同步执行代码,避免析构后,多线程同时操作造成崩溃,该门卫可以放入步骤一中的that类合并实现,注意不能用std::mutex(有可能产生递归加锁)
三是母体析构函数中如果一时处理不完,有后续动作,可在that类中加入回调功能,在母体中设置一个回调函数,在该函数中可以做一些善后工作(说明:函数代码不会随对象销毁而销毁,该代码中不能处理已经销毁/释放的数据)

from uv-cpp.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.