I use DispEventAdvise in a BHO in order to capture onclick events of a specific checkbox. You can see the code in my previous question (although it's not that relevant).
In order to be able to call DispEventUnadvise later, I keep a reference to the IHTMLElement object of the checkbox.
When should I call DispEventUnadvise? Is there a way to know when the checkbox is going away?
Is it even legal to keep a reference to the IHTMLElement object? I mean, when the page is destroyed, and there's still a reference to the object of that checkbox, what happens to it?
You are expected to unadvise from event source/connection point when you no longer want to receive events. The call, in particular, make the connection point release your sink interface pointer. Before unadvising, connection point holds a reference and extends your sink object lifetime.
That is, you call it any time you want to opt out, there is no specific good time where you should do it at, other than general considerations.
The other part of the question "when checkbox is going away" however is not related directly. Being connected to connection point you don't receive "going away" notification. It is legal to keep holding an interface pointer even if the entire page went away: the checkbox, alone or together with its owner, will remain in terminating state until all external references (including yours) are released. As a part of safe termination, when the page/document goes away it might strip connection point connections from its side because no events are going to follow and the document is doing sanity cleanup to avoid circular references and leaks.
In your case, I suppose your best way out is to find another suitable event to see when the entire document goes away and assume that checkbox is going away as well. Another [less safe] option is to watch your sink interface object: once its external reference is unexpectedly release by connection point, it means that its doing cleanup and checkbox is going away.
Related
TL;DR
How do I correctly pass information, wrapped as a QObject to QML in a signal that might be emitted with high frequency, reducing overhead, ensuring the object/reference outlives at least the execution of the connected slots?
I have a C++ QObject registered as QML type. This object has some signal
void someSignal(InformationQObject* someInformation)
in which I don't pass all the information in seperate parameters but in one object - similar to the signals found e.g. in the MouseArea whith e.g. the signal
void clicked(QQuickMouseEvent *mouse)
Now I am wondering about the right lifetime management of this someInformation.
So far, in my object, I have a member:
InformationQObject* m_lastInformation
and to send the signal I use:
void sendMySignal(/* possible params */)
{
delete m_lastInformation
m_lastInformation = new InformationQObject(/* right params here */)
emit someSignal(m_lastInformation)
}
Now this seems wrong.
Reasons: If you look at the implementation of the QQuickMouseArea they do it differently. Seemingly they don't create a new object for each event but recycle the existing one, seemingly. I find it hard to follow all their sources but I think this comment from one of their files gives a good reason:
QQuickPointerEvent is used as a long-lived object to store data related to
an event from a pointing device, such as a mouse, touch or tablet event,
during event delivery. It also provides properties which may be used later
to expose the event to QML, the same as is done with QQuickMouseEvent,
QQuickTouchPoint, QQuickKeyEvent, etc. Since only one event can be
delivered at a time, this class is effectively a singleton. We don't worry
about the QObject overhead because the instances are long-lived: we don't
dynamically create and destroy objects of this type for each event.
But this is where it gets to complicated for me to see through, how they do it. This comment is regarding a QQuickPointerEvent. There exists a QQuickPointerMouseEvent. In their signal they pass a QQuickMouseEvent*
The latter is a pointer to one of their members QQuickMouseEvent quickMouseEvent.
At some point, somehow, this pointer becomes invalid in QML
MouseArea {
anchors.fill: parent
property var firstEvent
onClicked: {
if (firstEvent === undefined) firstEvent = mouse
console.log(mouse.x, mouse.y)
console.log(firstEvent.x, firstEvent.y) // -> TypeError on second and consecutive clicks.
}
}
So there must be some magic happening, that I don't understand.
You are opening a can of worms. QML lifetime management is broken in above-trivial scenarios, and the API doesn't really give you a meaningful way to walk around that. The solution for me has been to set the ownership to CPP and manually manage the object lifetime. Primitive I know, but the only solution to avoid deletion of objects still in use and actual hard crashes.
If mouse area recycled the same event object, it wouldn't become invalid on the subsequent click.
If your code reflects your actual usage scenario, I recommend you simply copy the individual event properties rather than attempting to store the actual event, either in dedicated properties, or as a JS object if you want to avoid overhead and don't need notifications. I tend to use arrays, and rely on the faster index access.
Another solution I can recommend is a Q_GADGET with a PIMPL - gadgets are limited by design so they cannot be passed as pointers, and they are always copied by value, but you can have the actual object only contain a pointer to the heavier data implementation, and only serve as an accessor and interface to access the data from QML. This way you can reuse the data stuff, with the actual object value being negligible, as it will essentially just be a pointer and involve no dynamic memory allocation whatsoever. You can additionally expose the actual data as an opaque object for the sake of copying that to other gadgets and use ref counting to manage the data lifetime.
I'm trying to figure out this problem.
Suppose, you have a code that uses boost::signals2 for communicating between objects. Lets call them "colorscales". Code for these colorscales is usually situated in the same DLL as the code that uses them. Let's call it main.dll
But sometimes code from other DLLs needs to use these objects and this is where the problems begin.
Basically, the application is pretty big and most of the DLLs are loaded to do some work and then they are unloaded. This is not the case with DLL that contain colorscales code, it's neved unloaded during application normal runtime.
So, when one of the DLLs is loaded (lets call it tools.dll) and some code runs, it may want to use these colorscale objects and communicate with them, so I connect to the signals these objects provide.
The problem is that boost is pretty lazy and all clever, and when you disconnect() slots, it doesn't actually erase connection and stuff that is associated with it (like boost::bind object and such). It just sets a flag that this connection is now disconnected and cleans it up on later (actually, it clean up 2 of these objects when you connect new slots and 1 of them when you invoke signal as of version 1.57). You probably already see where this is coming to.
So, you when you don't need more tools, you disconnect these signals and then application unloads tools.dll.
Then at a later stage, some code executes from the main.dll which causes one of colorscale signals invoked. boost::signals2 goes to invoke it, but before it tries to clean up one disconnected slot. This is where access violation happens, because internally connection had a shared_state object or something like this, that tries to clean itself up in a thread-safe way. But it faces the problem, that the code that it tries to call is already not there, because DLL is unloaded, so the Access Violation exception is thrown.
I've tried to fix this by invoking signal with some dummy parameters before DLL is unloaded and also by connecting and then disconnecting more slots (this one was a stupid idea, because it doesn't solve problem, but just multiplies it) some predefined amount of times (2 or 3 times more than there are slots at all).
It worked, or I thought so, because now it doesn't crash instantly, but rather crashes the next time you load the same tools.dll. I still need to figure out where and why does it crash, but it's somewhere else inside boost.
So, I wanted to ask, what are my options of fixing it?
My thoughts were
Implementing my own connection that works in a more simple way
Providing a more simple way to communicate, like, callbacks, for instance
Finding a workaround for boost being so lazy and smart.
Well, it seems that I've found the cause of the crash after the fix.
So, basically, what happens, when you use the workaround described above (calling signal with dummy parameters multiple times), what it does is that it replaces _shared_state object that was created from boost code from main.dll by another _shared_state object that is created from boost code from tools.dll. This object maintains pointer to reference counter (of type derived from boost::detail::sp_counter_base) inside.
Then the tools.dll unloads and the object remains, but its virtual table is pointing to the code that is no longer there. Let's look at the virtual table of the reference counter to understand what's going on.
[0] 0x000007fed8a42fe5 tools.dll!boost::detail::sp_counted_impl_p<...>::`vector deleting destructor'(unsigned int)
[1] 0x000007fed8a4181b tools.dll!boost::detail::sp_counted_impl_p<...>::dispose(void)
[2] 0x000007fed8a4458e tools.dll!boost::detail::sp_counted_base::destroy(void)
[3] 0x000007fed8a43c42 SegyTools.dll!boost::detail::sp_counted_impl_p<...>::get_deleter(class type_info const &)
[4] 0x000007fed8a42da6 tools.dll!boost::detail::sp_counted_impl_p<...>::get_untyped_deleter(void)
As you can see, all these method are connected to the disposal of reference counter, so the problem doesn't arise before you try to do the same trick second time. So, the trick with disconnecting all signals to try to get rid of all the code from tools.dll doesn't work as expected and the next time you try to do the trick, Access Violation occurs.
i'd like to perform some actions on a particular entity after there are no longer any references to it, but before the garbage collector wipes its data out. i'm using this for an experiment with more "purely functional" gui abstractions. here is what i'd like to do:
(let [window (make-window width height)] ; A
(various-actions window)
(let [window (resize window new-width new-height)] ; B
(more-actions window))
(and-more-actions window)) ; C
at A a window instance is created with a width and height. eventually i want to change the window at B. the code treats this like an immutable action, but underneath the window will simply change to reflect the changes. actions performed on the A scope's window while the B scope's window exists (in case of multithreading) would not be allowed in some manner.
at C after we finish doing stuff at B and leave that let scope, the B window object will be unreferenced and garbage collected. but i want to signal the underlying window mechanism that it should roll back the B changes now, and accept A scope activity again. thus action at C will be as though B effects didn't happen.
as well, if the top level A window is no longer referenced, it should destruct itself in whatever manner before garbage collection.
i could possibly manage this by having make-window modify a global state which registers window references, but i'm not sure how to detect the point at which the B scope reference is lost. how can i check the references to a piece of data? or is there some other way to address this problem?
i realize this is a somewhat convoluted set-up, but i want to find a way to reconcile the statefulness of gui programming and make it appear to be as pure as possible.
This is not the way to build a correct program. A correctly-written program cannot assume that garbage collection is ever run, and certainly it won't run as instantaneously as you'd like in order to make a UI decision based on it.
It's not at all clear from your problem description what you actually want to do, but tying it to garbage collection is sure to be the wrong way to do it. Perhaps you could add some code after leaving B that will do whatever it is that you want.
Please note - these builds are for VS2008/VS2010 builds I cannot use any 11 constructs.
Imagine I have subscribers listening to some publisher. My publisher has a container of subscriber pointers. In my void detach(ISubscriber *), instead of locking the subscriber list, I will "NULL" out the pointer, for lack of a better word, for that subscriber.
//My container in the publisher. Inserts to not invalidate, removals only invalidate iterators pointing to the removed element, for this reason we NULL
Container<ISubscriber *> myContainer;
Now in the publisher...
void NotifySubscribers(){
foreach(subscriber in container){
if(subscriber)//This is my problem
subscriber->notify()
}
}
Line 3 - pointer is tested and is pointing to valid object.
Before line 4 is executed, another thread NULLs the subscriber.
Line 4 - Boom.
My Question, is there a way that I can use some sort of Interlocked something such that the test and call is atomic.
e.g. for a reference counted object in the destructor, something like this works
RefCountObject::~RefCountObject(){
if(InterlockedDecrement(&m_count) == 0)
delete m_data;
}
Here, the reference counter is decremented and tested against zero automically, then and only then if equal to zero, the data is released.
Is there a way for me to do this for calling a function based on the validity of a pointer?
Edit 1: I need to clarify a little based on the comments and thank you for your replies. The publisher is not responsible for the "releasing of memory" of the Subscribers, so there will be no leak. After the notify, the publisher will go through a loop that cleans up the container by removing nulled out subscribers.
Now as for the subscribers themselves. When they detach, they are just detaching from listening to the publisher. They themselves will live on in static objects (This is the contract we are requiring). Why? Because we cannot afford to hold a lock during notification. The only other option was to use Share_Ptr, which was decided not to be incorporated into this DLL, due to versioning in the future.
I created a hand written shared_ptr, but then it occurred to me that any reference to an object that was not wrapped in a resource management class would fall into the same pitfall and just push the "requirement" that subscribers would have to make sure to not refer to any dangling references within their implementation of said subscriber.
Which brings us back to just saying, subscribers cannot be "released", and currently all the clients that will use this are static objects. We were just looking towards the future. Some of the users are legacy apps and would not be easy to bring in enabled_shared_from_this etc.
is there a way that I can use some sort of Interlocked something such that the test and call is atomic.
For the test, yes there will be a way. You just want to compare a pointer.
To do the call, i doubt it. You will need a guard around the call, i.e. a Critical Section.
You can use a "smart pointer" strategy to do a deferred nulling of the pointer. As long as someone has a reference to the pointer, as determined by an interlocked reference count, keep the pointer valid; when the count goes to zero it's safe to null.
I have an object (Client * client) which starts multiple threads to handle various tasks (such as processing incoming data). The threads are started like this:
// Start the thread that will process incoming messages and stuff them into the appropriate queues.
mReceiveMessageThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)receiveRtpMessageFunction, this, 0, 0);
These threads all have references back to the initial object, like so:
// Thread initialization function for receiving RTP messages from a newly connected client.
static int WINAPI receiveRtpMessageFunction(LPVOID lpClient)
{
LOG_METHOD("receiveRtpMessageFunction");
Client * client = (Client *)lpClient;
while(client ->isConnected())
{
if(client ->receiveMessage() == ERROR)
{
Log::log("receiveRtpMessageFunction Failed to receive message");
}
}
return SUCCESS;
}
Periodically, the Client object gets deleted (for various good and sufficient reasons). But when that happens, the processing threads that still have references to the (now deleted) object throw exceptions of one sort or another when trying to access member functions on that object.
So I'm sure that there's a standard way to handle this situation, but I haven't been able to figure out a clean approach. I don't want to just terminate the thread, as that doesn't allow for cleaning up resources. I can't set a property on the object, as it's precisely properties on the object that become inaccessible.
Thoughts on the best way to handle this?
I would solve this problem by introducing a reference count to your object. The worker thread would hold a reference and so would the creator of the object. Instead of using delete, you decrement from the reference count and whoever drops the last reference is the one that actually calls delete.
You can use existing reference counting mechanisms (shared_ptr etc.), or you can roll your own with the Win32 APIs InterlockedIncrement() and InterlockedDecrement() or similar (maybe the reference count is a volatile DWORD starting out at 1...).
The only other thing that's missing is that when the main thread releases its reference, it should signal to the worker thread to drop its own reference. One way you can do this is by an event; you can rewrite the worker thread's loop as calls to WaitForMultipleObjects(), and when a certain event is signalled, you take that to mean that the worker thread should clean up and drop the reference.
You don't have much leeway because of the running threads.
No combination of shared_ptr + weak_ptr may save you... you may call a method on the object when it's valid and then order its destruction (using only shared_ptr would).
The only thing I can imagine is to first terminate the various processes and then destroy the object. This way you ensure that each process terminate gracefully, cleaning up its own mess if necessary (and it might need the object to do that).
This means that you cannot delete the object out of hand, since you must first resynchronize with those who use it, and that you need some event handling for the synchronization part (since you basically want to tell the threads to stop, and not wait indefinitely for them).
I leave the synchronization part to you, there are many alternatives (events, flags, etc...) and we don't have enough data.
You can deal with the actual cleanup from either the destructor itself or by overloading the various delete operations, whichever suits you.
You'll need to have some other state object the threads can check to verify that the "client" is still valid.
One option is to encapsulate your client reference inside some other object that remains persistent, and provide a reference to that object from your threads.
You could use the observer pattern with proxy objects for the client in the threads. The proxies act like smart pointers, forwarding access to the real client. When you create them, they register themselves with the client, so that it can invalidate them from its destructor. Once they're invalidated, they stop forwarding and just return errors.
This could be handled by passing a (boost) weak pointer to the threads.