Sunday, 15 September 2013

c++ - How to detect QObject::moveToThread() failure in Qt5? -



c++ - How to detect QObject::moveToThread() failure in Qt5? -

the documentation on qobject::movetothread() qt5.3 explains movetothread() method can fail if object has parent. how observe failure in code?

i realize making sure object not have parent first enough, defensive programming practice test homecoming value calls may fail.

edit: want stress here after answers aware can test if parent 0 before calling movetothread. looking possible ways determine empirically movetothread phone call succeeded.

to reliably result of movetothread(), grab threadchange event of object undergoing move (by overriding qobject::event() or installing event filter), , store whether event has been seen in reference local variable:

static bool moveobjecttothread(qobject *o, qthread *t) { class eventfilter : public qobject { bool &result; public: explicit eventfilter(bool &result, qobject *parent = nullptr) : qobject(parent), result(result) {} bool eventfilter(qobject *, qevent *e) override { if (e->type() == qevent::threadchange) result = true; homecoming false; } }; bool result = false; if (o) { o->installeventfilter(new eventfilter(result, o)); o->movetothread(t); } homecoming result; }

long story:

the documentation wrong. can move qobject parent thread. so, need phone call movetothread() on root of qobject hierarchy want move, , children moved, (this ensure parents , children on same thread). academic distinction, know. beingness thorough here.

the movetothread() phone call can fail when qobject's thread() isn't == qthread::currentthread() (ie. can push object to, not pull 1 from thread).

the lastly sentence lie-to-children. can pull object if has before been dissociated thread (by calling movetothread(nullptr).

when thread affinity changes, object sent qevent::threadchange event.

now, question how reliably observe move happened. reply is: it's not easy. obvious first thing, comparing qobject::thread() homecoming value after movetothread() phone call argument of movetothread() not idea, since qobject::thread() isn't (documented be) thread-safe (cf. the implementation).

why problem?

as movetothread() returns, moved-to thread may have started executing "the object", ie. events object. part of processing, object might deleted. in case next phone call qobject::thread() on original thread dereference deleted data. or new thread hand off object yet thread, in case read of fellow member variable in phone call thread() in original thread race against write same fellow member variable within movetothread() in new thread.

bottomline: accessing movetothread()ed object original thread undefined behaviour. don't it.

the way forwards utilize threadchange event. event sent after failure cases have been checked, but, crucially, still originating thread (cf. the implementation; plain wrong send such event if no thread alter happened).

you can check event either subclassing object move , reimplementing qobject::event() or installing event filter on object move.

the event-filter approach nicer, of course, since can utilize qobject, not can or want subclass. there's problem, though: event has been sent, event processing switches new thread, event filter object hammered 2 threads, never idea. simple solution: create event filter kid of object move, moved along it. that, on other hand, gives problem how command lifetime of storage can result if moved object deleted when reaches new thread. create long story short: storage needs reference variable in old thread, not fellow member variable of object beingness moved or event filter. accesses storage originating thread, , there no races.

but, but... isn't still unsafe? yes, if object moved again thread. in case, event filter access storage location first moved-to thread, , race read access originating thread. simple solution: de-install event filter after has fired once. implementation left exercise reader :)

c++ multithreading return-value qt5 defensive-programming

No comments:

Post a Comment