es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Intento ilegal de conectar a una variable que se encuentra en un hilo diferente al del motor QML.

He creado un objeto (que hereda de QObject) en mi main.cpp y estoy pasando este objeto a otro hilo. Para simplificar las cosas, mi main se ve así:

main.cpp

QGuiApplication app(argc, argv);
ClientListWrapper clients;   // Hereda de QObject
if (!clients.initialize())
    return -1;
args2thread->Pointer2clients = &clients;     // Pasando este objeto al hilo
std::thread Listening_thread(thread_function, args2thread);  // Creando un hilo

Ahora en mi función de hilo estoy modificando el objeto clients, es decir:

myThread.cpp

// Recibir datos del cliente aquí
.
args2thread->clients->addClient(data);  // Almacenar los datos recibidos
.

QT responde con los siguientes errores en tiempo de ejecución:

QObject: No se pueden crear hijos para un padre que está en un hilo diferente.
QQmlEngine: Intento ilegal de conectarse a Client(0x11198860) que está en un hilo diferente al motor QML QQmlApplicationEngine.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El mensaje de error indica que no podemos realizar cambios en un QObject que fue creado en un hilo desde otro hilo. En este caso, el objeto ClientListWrapper fue creado en el hilo principal y se pasó al Listening_thread. Cuando thread_function intenta modificar el objeto ClientListWrapper, lo está haciendo desde un hilo diferente, lo que causa errores en tiempo de ejecución.

    Para solucionar este problema, debemos asegurarnos de que todas las modificaciones al objeto ClientListWrapper se realicen desde el mismo hilo que lo creó. Una forma de lograr esto es usar la clase QThread de Qt en lugar de std::thread. Podemos crear una subclase de QThread y mover el objeto ClientListWrapper al nuevo hilo utilizando QObject::moveToThread():

    class ListeningThread : public QThread
    {
    public:
        explicit ListeningThread(ClientListWrapper* clients)
            : m_clients(clients)
        {}
    
    private:
        void run() override
        {
            // Recibir datos del cliente aquí
            ...
            QMetaObject::invokeMethod(m_clients, "addClient", Qt::AutoConnection, Q_ARG(...));
            ...
        }
    
        ClientListWrapper* m_clients;
    };
    
    int main(int argc, char** argv)
    {
        QGuiApplication app(argc, argv);
        ClientListWrapper clients;   // Hereda de QObject
        if (!clients.initialize())
            return -1;
    
        ListeningThread thread(&clients);
        clients.moveToThread(&thread);
        thread.start();
        ...
    }
    

    En esta solución, creamos un objeto ListeningThread que toma un puntero al objeto ClientListWrapper. Luego llamamos a moveToThread() para mover el objeto ClientListWrapper al nuevo hilo. Finalmente, llamamos a start() para iniciar el hilo.

    En el método run() de ListeningThread, ahora podemos realizar modificaciones de forma segura en el objeto ClientListWrapper utilizando QMetaObject::invokeMethod() con el parámetro AutoConnection. Esto garantiza que la llamada al método se ejecute en el contexto del nuevo hilo.

    Usar QThread y moveToThread() es una forma más sencilla y compatible con Qt de manejar el multihilo en las aplicaciones de Qt. Nos permite evitar problemas comunes, como modificar QObjects desde múltiples hilos.

Comments are closed.