⚠️ Forum Maintenance: Feb 6th, 8am - 14pm (UTC+2)

Invoking QObject (derivate) member functions on multiple threads

  • Hi!

    My problem is that I am currently baking a class to do multi-threaded OpenCL-GL interop class. Ultimate goal is create a an InteropWindow class similar to the OpenGLWindow example, but that takes care of all the boilerplate regarding the interop setup.

    Thus I have two init function, one for both APIs, and also two "do" functions, render and compute. What I want to achieve is have two OpenGL contexts (actually 3, one extra for a UI overlay) which are sharing resources and be able to make them current on two different threads, one doing OpenGL render while the other is doing OpenCL compute. This is all fine, so long as the programmer makes a promise that he/she synchronizes shared resource usage correctly using cl_khr_gl_event and ARB_cl_event.

    I want to end-user to be able to subclass InteropWindow, override the critical functions and be done with it. However, I do not want the synchronization to manifest in the public interface of InteropWindow, meaning define entry points such as:

    void InteropWindow::render(GLsync compute)

    or even worse

    void InteropWindow::render(QVector<GLsync> compute)

    and the other way around, because the number of shared resources that impose sync points are highly use-case specific, and heap allocating params only to pass from one part to the other per frame is not sexy. These primitives must be member variables of the derived class.

    However, if

    void InteropWindow::render()
    void InteropWindow::compute()

    are member functions and I want to invoke them on separate threads from base class logic (InteropWindow), then I need to do something tricky. InteropWindow cannot belong to 2 separate QThreads to process signals, and this fairly old topic states it is unadvised to invoke member functions of a QObject from a different thread. (Some even claim it is not even possible in C++) An ordinary std::function does the trick, which I could use in 2 helper classes,

    class RenderThread : QThread {...};
    class ComputeThread : QThread {...};

    both which would override QThread::run() methods to invoke this std::function, which wraps the member functions

    void InteropWindow::render()
    void InteropWindow::compute()

    with the appropriate this pointer, which is possible, if both are members of InteropWindow.

    My knowledge of Qt is not enough to be able to tell if hell will break loose if I do this. Is this good practice? Is there a better way to do this? I really do not wish to sacrifice the elegance of being able to subclass InteropWindow only, and be done with it: providing the means of overriding compute/render functions and providing the context for the data storage and sync primitive storage that are visible from both overriden functions.

    Thanks in advance,

Log in to reply