Richard Bateman
unread,Jul 2, 2012, 11:45:56 AM7/2/12Sign in to reply to author
Sign in to forward
You do not have permission to delete messages in this group
Either email addresses are anonymous for this group or you need the view member email addresses permission to view the original message
to firebre...@googlegroups.com
Comments in-line
On Jul 1, 2012, at 17:12 , Adrian C wrote:
> I have created a collection of scriptable objects by exposing in MyPluginAPI a property that returns an array, initialized like this:
>
> m_collection = m_host->getDOMWindow()->createArray();
>
> Then thanks to Richard, I learned how to push my custom objects into that array. I just defined my new class derived from JSAPIAuto and do this:
>
> MyObjectPtr newMyObject = boost::make_shared<MyObject>(m_host, [...other constructor parameters...]));
> m_collection->Invoke("push", FB::variant_list_of(newMyObject));
>
> All this works very well. I can browser the collection from JavaScript, use properties and invoke methods in the objects in the collection.
>
> Now I have a working thread that monitors changes and when they happen I want to fire an event that includes a reference to one of the items in the above collection. The working thread has access to a native C array provided by the OS API and the array defines an LPVOID member for each element of the array. So I wanted to use that pointer to reference each of the objects and when the event happens, try to use it in the call.
>
> First, to pass the objects from the main thread to the working thread, I created a shared_ptr to the original MyObjectPtr to cast it to LPVOID. I am not sure whether this is necessary or valid.
>
> MyObjectPtr *ppMyObject = new MyObjectPtr(newMyObject);
> m_rgNative[i].pvUserData = (void*)ppMyObject;
This is unneccesary and potentially dangerous. The reference counting on boost::shared_ptr is threadsafe, though destruction is not. That means that you're fine to access the ptr from another thread as long as you're careful with it (all normal rules for accessing the same object on multiple threads apply) but make sure that the last release happens on the main thread.
> Then in the workin thread, I try to get the pointer back to retrieve the reference to the object. I know that in COM you can't pass COM objects across threads without complex marshaling. Does one of the many fantastic features of Firebreath includes taking care of this?
>
> MyObjectPtr *ppMyObject = (MyObjectPtr*)(m_rgNative[i].pvUserData);
> MyObjectPtr theMyObject = *ppMyObject;
> delete ppMyObject;
> theMyObject->set_someproperty(value); <- this seems to work.
You're really over thinking this; it's just an object. This isn't COM, so you don't have to worry about that. However, make sure that anything that may be accessed from javascript or from your alternate thread are threadsafe.
> The last statement above seems to work, I can actually set properties in my custom object across threads. But I am not sure again if it's valid. Besides, I think it fails if the object is busy, so it might not be the correct solution to the interthread communication.
You can probably solve a lot of the potential issues simply by throwing a mutex into your getters, setters, and methods.
> And then, last, I have no clue how to reference the original object in the fire event method. For the time being, it's working fine if the event is defined as:
>
> FB_JSAPI_EVENT(statuschange, 2, (const FB::variant&, const int));
> and fired from the working thread calling
This should work fine; FB::variant is actually what it will end up being. If you do this then you can pass whatever (supported) type you want for the first parameter.
> fire_statuschange(std::wstring(m_rgNative[i].szName), m_rgNative[i].dwCurrentState);
>
> But since I don't want a string, but a reference to the scriptable object, I tried to change the event definition to:
>
> FB_JSAPI_EVENT(statuschange, 2, (const FB::JSObjectPtr&, const int));
> and fired from the working thread calling
> fire_statuschange(theMyObject, m_rgNative[i].dwCurrentState);
This should work as well; if it doesn't, truy passing just a FB::JSObjectPtr without the const &; I don't know of a reason that the const & wouldn't work, but that's the only explanation I can think of.
One of your biggest issues is that you are seriously over-thinking the cross thread stuff. Basically when you're dealing with multiple threads in normal C++ the only real concern is that you could have two things accessing it at the same time; if one changes something while another is running then you could run into some problems, and you could definitely have an issue if the last two shared_ptr instances go away at the same time on different threads because they could both try to destruct your object, but otherwise it's just a variable in memory shared between both threads. Note that fire_* will always fire that event on the main thread asynchronously.
An FB::JSObjectPtr object will also automatically cause all calls that modify data to happen on the main thread; this is usually good, but be aware that if you are doing a lot of operations one after another from a different thread you may want to wrap them all in a function and use m_host->CallOnMainThread to call it; each call that happens on the main thread adds a reasonably significant amount of delay to the call, so you can run into performance problems that way if you aren't careful.
Hope that helps,
Richard