[Interest] QMetaObject::invokeMethod thread safety

Matthew Woehlke mwoehlke.floss at gmail.com
Fri May 17 19:25:15 CEST 2019


Yes, yes, I know the doc says it's thread safe, but I'm still not
entirely sure about this particular example:

  QPointer<Foo> foop; // global

  void bar1()
  {
    auto* foo = new Foo;
    foop = foo;
    QtConcurrent::run(&bar2);

    // ...later...
    delete foo;
  }

  void bar2()
  {
    QMetaObject::invokeMethod(foop, &Foo::whatever, ...);
  }

IOW, I have some shared object owner by Thread 1 which is eventually
deleted. In Thread 2, I want to queue a call to a slot on that object.

Historically I have used a shared pointer to pass the object between
threads, because I *know* that is safe (the call will be queued before
the object can possibly be deleted; if it gets deleted before the queued
call dispatches, that's okay; I just care that the program doesn't crash
/ corrupt memory / eat kittens). If, OTOH, I were to use a bare pointer,
I *know* that is unsafe, because I have no guarantee the object still
exists (or, worse, that the pointer now refers to some other object)
when I go to queue the call.

What's less clear (without trying to dig through the guts of Qt's event
queuing at least) is; in something like the above, is invokeMethod is
guaranteed to be able to queue the call successfully if another thread
deletes the target object some time between the start of the call to
invokeMethod and when the event is fully created on Foo's thread's event
queue (at which point it is "safe")?

In fact, given that invokeMethod takes a QObject* and not a QPointer, I
think the answer is that it *can't* be fully thread-safe? (If the caller
does not own the target object, how could Qt prevent the passed-in
pointer from being destroyed and recycled between the caller obtaining
the QObject* from the QPointer and the first instruction of invokeMethod
executing?)

-- 
Matthew



More information about the Interest mailing list