强制删除插槽中的boost :: signals2 [英] Force deletion of slot in boost::signals2

查看:271
本文介绍了强制删除插槽中的boost :: signals2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现的boost :: signals2使用排序一个懒惰删除连接的插槽,这使得它很难使用的东西,管理对象的生命周期的连接。我正在寻找一种方式来迫使插槽,可以直接删除时断开。如何通过设计我的code,以解决此问题的任何想法不同,也AP preciated!

I have found that boost::signals2 uses sort of a lazy deletion of connected slots, which makes it difficult to use connections as something that manages lifetimes of objects. I am looking for a way to force slots to be deleted directly when disconnected. Any ideas on how to work around the problem by designing my code differently are also appreciated!

这是我的情况:我有责任做的事情需要时间不同步,看起来像这样(简体)命令类:

This is my scenario: I have a Command class responsible for doing something that takes time asynchronously, looking something like this (simplified):

class ActualWorker {
public:
    boost::signals2<void ()> OnWorkComplete;
};

class Command : boost::enable_shared_from_this<Command> {
public:
    ...

    void Execute() {
        m_WorkerConnection = m_MyWorker.OnWorkDone.connect(boost::bind(&Command::Handle_OnWorkComplete, shared_from_this());

        // launch asynchronous work here and return
    }

    boost::signals2<void ()> OnComplete;

private:
    void Handle_OnWorkComplete() {
        // get a shared_ptr to ourselves to make sure that we live through
        // this function but don't keep ourselves alive if an exception occurs.
        shared_ptr<Command> me = shared_from_this();

        // Disconnect from the signal, ideally deleting the slot object
        m_WorkerConnection.disconnect();

        OnComplete();

        // the shared_ptr now goes out of scope, ideally deleting this
    }

    ActualWorker m_MyWorker;
    boost::signals2::connection m_WorkerConnection;
};

类调用大约是这样的:

The class is invoked about like this:

...
boost::shared_ptr<Command> cmd(new Command);
cmd->OnComplete.connect( foo );
cmd->Execute();
// now go do something else, forget all about the cmd variable etcetera.

Command类保持自身活着通过让一个shared_ptr本身是使用boost ::绑定绑定到ActualWorker信号。

the Command class keeps itself alive by getting a shared_ptr to itself which is bound to the ActualWorker signal using boost::bind.

当工人完成后,在命令处理程序被调用。现在,因为我想Command对象被摧毁,我从信号断开作为可以在code可以看出以上。的问题是,实际的槽对象不会被删除断开时,它仅标记为无效,然后在稍后的时间被删除。这又似乎取决于信号再次触发,它不会在我的情况做,导致从不过期插槽。升压::绑定对象从而永不熄灭的范围,拿着一个shared_ptr我的目标永远不会被删除。

When the worker completes, the handler in Command is invoked. Now, since I would like the Command object to be destroyed, I disconnect from the signal as can be seen in the code above. The problem is that the actual slot object is not deleted when disconnected, it is only marked as invalid and then deleted at a later time. This in turn appears to depend on the signal to fire again, which it doesn't do in my case, leading to the slot never expiring. The boost::bind object thus never goes out of scope, holding a shared_ptr to my object that will never get deleted.

我可以解决此通过使用该指针,而不是一个shared_ptr绑定,然后使用一个成员shared_ptr的,然后我在处理函数释放保持我的对象还活着,但它那种使得设计感觉有点过于复杂。有没有办法断开时强制signals2删除插槽?还是有别的东西我可以做些什么来简化设计?

I can work around this by binding using the this pointer instead of a shared_ptr and then keeping my object alive using a member shared_ptr which I then release in the handler function, but it kind of makes the design feel a bit overcomplicated. Is there a way to force signals2 to delete the slot when disconnecting? Or is there something else I could do to simplify the design?

任何意见都AP preciated!

Any comments are appreciated!

推荐答案

最后我做我自己的(子)实现的信号,主要的要求是一个插槽应该通过调用连接断开::(被销毁)。

I ended up doing my own (subset) implementation of a signal, the main requirement being that a slot should be destroyed by a call to connection::disconnect().

实施一起存储在从插槽中实现指针的地图中的所有插槽,一个shared_ptr换一个插槽实现,而不是一个列表/向量,从而使快速访问个人插槽,而不必遍历所有插槽的信号线进入。一个插槽实现是在我的情况基本上是一个boost ::功能。

The implementation goes along the lines of the signal storing all slots in a map from slot implementation pointer to a shared_ptr for a slot implementation instead of a list/vector, thereby giving quick access to individual slots without having to iterate over all slots. A slot implementation is in my case basically a boost::function.

连接有一个的weak_ptr到内部实现类的信号和的weak_ptr于槽实现类型,以允许信号出去的范围,并使用时隙指针作为钥匙插入信号图,以及一个指示关于连接是否仍然有效(不能使用作为有可能被重新使用原始指针)。

Connections have a weak_ptr to the internal implementation class for the signal and a weak_ptr to the slot implementation type to allow the signal to go out of scope and to use the slot pointer as the key into the signal map as well as an indication on whether the connection is still active (can't use a raw pointer as that could potentially be reused).

当断开被调用时,这两个弱指针被转换为shared_ptrs并且如果这两个成功,该信号实现请求断开由指针给定的槽。这是通过简单的从地图上抹去完成它。

When disconnect is called, both of these weak pointers are converted to shared_ptrs and if both of these succeed, the signal implementation is asked to disconnect the slot given by the pointer. This is done by simple erasing it from the map.

该地图由互斥锁保护的,允许多线程使用。到prevent死锁,互斥不保持而调用槽,然而,这意味着,一个时隙可从一个不同的线程正好由信号被调用之前被断开。这也与常规升压:: signals2和在这两个方案之一需要能够从一个已断开甚至之后的信号处理的回调的情况下

The map is protected by a mutex to allow for multithreaded use. To prevent deadlocks, the mutex is not held while calling the slots, however this means that a slot may be disconnected from a different thread just prior to being called by the signal. This is also the case with regular boost::signals2 and in both of these scenarios one needs to be able to handle a callback from a signal even after one has disconnected.

要简化code当信号被激发,我强迫在此要断开所有插槽。这是从boost :: signals2,但这插槽列表的副本美其名曰为了处理断开/连接,同时发射信号之前有所不同。

To simplify the code for when the signal is fired, I am forcing all slots to be disconnected during this. This is different from boost::signals2, that does a copy of the list of slots before calling them in order to handle disconnections/connections while firing the signal.

以上很适合我的场景,其中感兴趣的信号很少解雇(在这种情况下,只有一次),但也有很多短期连接的,使用的时候,否则占用大量的内存,即使在这个问题把戏概述。

The above works well for my scenario, where the signal of interest is fired very seldom (and in that case only once) but there are a lot of short-lived connections that otherwise use up a lot of memory even when using the trick outlined in the question.

有关其他情况下,我已经能够只是一个推动替代使用的信号::功能(因此要求只能有一个连接),或者只是在问题与解决方法贴在哪里监听器本身管理其生命周期。

For other scenarios, I've been able to replace the use of a signal with just a boost::function (thus requiring that there can only be a single connection) or just by sticking with the workaround in the question where the listener itself manages its lifetime.

这篇关于强制删除插槽中的boost :: signals2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆