Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Passing custom type pointers between QML and threads via signals and slots cause app to crash
QtWS25 Last Chance

Passing custom type pointers between QML and threads via signals and slots cause app to crash

Scheduled Pinned Locked Moved Solved General and Desktop
qthreadqmlmultithreadingqvariantsignals & slots
13 Posts 4 Posters 3.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M Offline
    M Offline
    Matthew11
    wrote on 20 May 2019, 13:16 last edited by Matthew11
    #1

    Hi, as topic partially described, I send pointers to my custom type object, which has 3 members (int, int and QVariant) via sig/slot between the main thread and the worker thread. I use the Controller - Worker approach from qt docs.

    Everything was fine when I have two int members in class, and it started crashing (SIGSEGV) since I have added QVariant member to exchange data between QML and C++.

    I'm guessing that crash is caused by accessing the shared resource (my custom class instance). I tried to add some serialization using QMutex, with and without QMutexLocker, QReadWriteLocker but the result was the same - crash. I also tried to protect the shared resource by applying Monitor construct wiki protecting the data with mutexes, but it also didn't work. At the moment I'm out of ideas and look for any help. Thanks in advance.

    Here is my code (plain text and link to git clone), program will probably crash after clicking the button or few spontaneous clicks. ContractorTask is my custom which I want to send using pointers.

    source:

    // ContractorTask.h
    
    #ifndef TASK_H
    #define TASK_H
    
    #include <QObject>
    #include <QVariant>
    #include <QThread>
    #include <QDebug>
    
    class ContractorTask : public QObject
    {
        Q_OBJECT
    
    public:
        explicit ContractorTask(QObject *parent = nullptr) :
            QObject(parent),
            taskID(-1),
            contractorID(-1),
            data("")
        {
            // ...
        }
    
        Q_INVOKABLE int getTaskID()
        {
            qDebug() << "getTaskID()" << QThread::currentThreadId();
            return taskID;
        }
    
        Q_INVOKABLE void setTaskID(int _ID)
        {
            qDebug() << "setTaskID()" << QThread::currentThreadId();
            taskID = _ID;
        }
    
        Q_INVOKABLE int getConctractorID()
        {
            qDebug() << "getConctractorID()" << QThread::currentThreadId();
            return contractorID;
        }
    
        Q_INVOKABLE void setContractorID(int _ID)
        {
            qDebug() << "setContractorID()" << QThread::currentThreadId();
            contractorID = _ID;
        }
    
        Q_INVOKABLE QVariant getData()
        {
            qDebug() << "getData()" << QThread::currentThreadId();
            return data;
        }
    
        Q_INVOKABLE void setData(QVariant _data)
        {
            qDebug() << "setData()" << QThread::currentThreadId();
            data = _data;
        }
    
    private:
        int taskID;
        int contractorID;
        QVariant data;
    };
    
    #endif // TASK_H
    
    // Contractor.h
    
    #ifndef CONTRACTOR_H
    #define CONTRACTOR_H
    
    #include <QObject>
    #include <QQmlEngine>
    #include <QThread>
    #include <QMutex>
    
    #include <ContractorTask.h>
    
    //#define CONTRACTOR_DEBUG_LOCK
    
    class Contractor : public QObject
    {
        Q_OBJECT
    
    public:
        Contractor(int _ID, QObject* parent = nullptr);
        ~Contractor();
    
        enum class Tasks : int
        {
            NOT_DEFINED = -1,
            Q_LIST_VARIANTS_TO_QML,
            GET_QVARIANT_FROM_QML
        };
    
        Q_ENUMS(Tasks)
    
        inline static void registerTasks()
        {
            qmlRegisterUncreatableType<Contractor>("Tasks", 1, 0, "ContractorTasks", "ContractorTask is uncreatable in QML");
        }
    
        int getID()
        {
            return ID;
        }
    
    public slots:
        void executeTask(ContractorTask* _task);
    
    signals:
        void finished();
        void taskStarted(ContractorTask* _task);
        void taskFinished(ContractorTask* _task);
    
    private:
        int ID;
    
    #ifndef CONTRACTOR_DEBUG_LOCK
        Qt::HANDLE mainThreadID;
    #endif
    };
    #endif // CONTRACTOR_H
    
    //Contractor.cpp
    
    #include "Contractor.h"
    
    #include <QDebug>
    #include <QThread>
    
    Contractor::Contractor(int _ID, QObject *parent) :
        QObject(parent),
        ID(_ID)
    {
    #ifndef CONTRACTOR_DEBUG_LOCK
        mainThreadID = QThread::currentThreadId();
    #endif
    }
    
    Contractor::~Contractor()
    {
        // ...
    
        qDebug() << "Cleaning SerialPortContractor...";
    }
    
    void Contractor::executeTask(ContractorTask* _task)
    {
        emit(taskStarted(_task));
    
        qDebug() << "\tCONTRACTOR STARTED";
    
        int localContractorID = _task->getConctractorID();
    
        if(localContractorID != getID())
        {
            qDebug() << "Not mine ID: " << localContractorID << "discarding";
            return;
        }
    
        qDebug() << "Emiting signal from Contractor";
        emit(taskStarted(_task));
    
        int localTaskID = _task->getTaskID();
        QVariant localData = _task->getData();
    
        QList<QVariant> _params;
        QList<float> _floats;
        _params = localData.value<QList<QVariant>>();
    
        for(auto item : _params)
        {
            _floats << item.toFloat();
        }
    
    #ifndef CONTRACTOR_DEBUG_LOCK
        qDebug() << "Main ThreadID =" << mainThreadID << "my ThreadID =" << QThread::currentThreadId();
    #endif
    
        switch(static_cast<Tasks>(localTaskID))
        {
        case Tasks::Q_LIST_VARIANTS_TO_QML :
        {
            QList<QVariant> _params;
            _params.append(12.5F);
            _params.append(14.36F);
    
            QVariant _data = _params;
    
            _task->setData(_data);
        }
            break;
        case Tasks::GET_QVARIANT_FROM_QML:
        {
            int i = 0;
            for(auto item : _floats)
            {
                qDebug() << "C++ item" << i++ << "value" << item;
            }
        }
            break;
        default:
        {
    #ifndef CONTRACTOR_DEBUG_LOCK
            qDebug() << "Oh... I don't have these one :(";
    #endif
        }
        }
    
        emit(taskFinished(_task));
    
        qDebug() << "\tCONTRACTOR ENDED";
    }
    
    // Controller.h
    
    #ifndef CONTROLLERv2_H
    #define CONTROLLERv2_H
    
    #include <QObject>
    #include <QThread>
    #include <QDebug>
    
    #include <Contractor.h>
    #include <ContractorTask.h>
    
    class Controller : public QObject
    {
        Q_OBJECT
        QThread workerThread;
    
    public:
        Controller()
        {
            Contractor *worker = new Contractor(0);
            worker->moveToThread(&workerThread);
            connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
            connect(this, &Controller::startTask, worker, &Contractor::executeTask);
            connect(worker, &Contractor::taskFinished, this, &Controller::handleResults);
            workerThread.start();
        }
    
        ~Controller()
        {
            workerThread.quit();
            workerThread.wait();
        }
    
    signals:
        void startTask(ContractorTask*);
    
    public slots:
        void handleResults(ContractorTask* _task)
        {
            qDebug() << _task->getTaskID() << _task->getConctractorID() << _task->getData();
        }
    };
    #endif // CONTROLLERv2_H
    
    // main.cpp
    
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <Controller.h>
    #include <QQmlContext>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        Contractor::registerTasks();
        Controller TaskController;
        ContractorTask Task;
    
        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("TaskController", &TaskController);
        engine.rootContext()->setContextProperty("Task", &Task);
    
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
    
        return app.exec();
    }
    
    // main.qml
    
    import QtQuick 2.12
    import QtQuick.Controls 2.5
    
    import Tasks 1.0
    
    ApplicationWindow {
        id: applicationWindow
        visible: true
        width: 640
        height: 480
        title: qsTr("Test")
    
        Button {
            id: button
            text: qsTr("Button")
            anchors.verticalCenter: parent.verticalCenter
            anchors.horizontalCenter: parent.horizontalCenter
    
            onClicked: {
                var items = [1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2]
    
                Task.setData(items)
                runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
            }
        }
    
        function runTaskFromQML(_taskId, _contractorID)
        {
            console.log("Running worker task from QML, ID = ", _taskId, " Contractor ID = ", _contractorID)
    
            Task.setTaskID(_taskId)
            Task.setContractorID(_contractorID)
            TaskController.startTask(Task)
        }
    }
    
    // .pro
    
    QT += quick
    CONFIG += c++11
    
    DEFINES += QT_DEPRECATED_WARNINGS
    
    SOURCES += \
            Contractor.cpp \
            main.cpp
    
    RESOURCES += qml.qrc
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    HEADERS += \
        Contractor.h \
        ContractorTask.h \
        Controller.h
    
    K 1 Reply Last reply 20 May 2019, 21:40
    0
    • M Offline
      M Offline
      Matthew11
      wrote on 25 May 2019, 20:02 last edited by Matthew11
      #13

      OK as @J.Hilk said:

      @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

      are you by any chance exposing those thread-shared custom types directly to qml?

      And:

      @J.Hilk said in Passing custom type pointers between QML and threads via signals and slots cause app to crash:

      I can only tell you that I always ran into trouble when I tried to access/manipulate c++ threaded stuff (directly)via QML.

      Indeed that was causing the crashes. The solution is to create a copy of the resource that is sent from QML and then send a copy of that resource to thread.

      As @J.Hilk suggested Manager object should do the job which is:

      @Matthew11 said in [Passing custom type pointers between QML and threads via signals and slots cause app to crash

      1. Manager <-> Threads :
      • communicate via signal/slots with QueuedConnection
      • synchronization/locking on the shared resource
      1. Manager <-> QML
      • signals and slots
      • or directly from the manager's memory

      Below you can find my working example. This is very similar to the code which I provided in the first post. You send a dispatch from QML to specific Contractor, Contractor then is doing his job and return the result back to QML (sends task with input data scenario). Or you send a dispatch to Contractor to retrieve some data (send task with no input data scenario). ContractorTask is no longer exposed to QML. But pointers are no longer send however it is possible in the C++ domain (across main (Manager) and workers threads with proper locking/synchronization).

      If you want to feel how it is when app is crashing uncomment the line _taskCopy.setData(_data); from pushTaskToContractor() in Controller.h which disabling the step of making the copy of the resource.

      Thank you all for your help in solving the problem!

      Code:

      //.pro
      
      QT += quick
      CONFIG += c++11
      
      SOURCES += \
              Contractor.cpp \
              main.cpp
      
      RESOURCES += qml.qrc
      
      HEADERS += \
          Contractor.h \
          ContractorTask.h \
          Controller.h
      
      // Contractor.h
      
      #ifndef CONTRACTOR_H
      #define CONTRACTOR_H
      
      #include <QObject>
      
      #include <ContractorTask.h>
      
      class Contractor : public QObject
      {
          Q_OBJECT
      
      public:
          Contractor(int _ID, QObject* parent = nullptr);
      
          int getID() { return ID; }
      
      public slots:
          void executeTask(ContractorTask _task);
      
      signals:
          void finished();
          void taskStarted(ContractorTask _task);
          void taskFinished(ContractorTask _task);
      
      private:
          int ID;
      };
      
      #endif // CONTRACTOR_H
      
      // Contractor.cpp
      
      #include "Contractor.h"
      
      #include <QDebug>
      #include <QThread>
      
      Contractor::Contractor(int _ID, QObject *parent) :
          QObject(parent),
          ID(_ID)
      {}
      
      void Contractor::executeTask(ContractorTask _task)
      {
          emit(taskStarted(_task));
      
          if(getID() != _task.getConctractorID())
          {
              qDebug() << "Not mine ID, discarding";
              return;
          }
      
          QVariant localData = _task.getData();
      
          switch(_task.getTaskID())
          {
          case 0: // PASS TASK TO C++ TO RETRIEVE DATA
          {
              QList<QVariant> _params;
              _params.append(12.5F);
              _params.append(14.36F);
      
              QVariant _data = _params;
      
              _task.setData(_data);
      
              qDebug() << "PASS TASK TO C++ TO RETRIEVE DATA";
          }
              break;
          case 1: // PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML
          {
              QList<QVariant> _params;
              _params = localData.value<QList<QVariant>>();
      
              QList<float> _floats;
              int counter = 0;
              for(auto item : _params)
              {
                  _floats << item.toFloat();
                  qDebug() << "Getting data in C++ from QML (QList<float>): item =" << counter++ << "value =" << item;
              }
      
              qDebug() << "PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML";
          }
              break;
          default:
          {
              qDebug() << "Oh... I don't have these one :(";
          }
          }
      
          emit(taskFinished(_task));
      }
      
      // ContractorTask.h
      
      #ifndef CONTRACTORTASK_H
      #define CONTRACTORTASK_H
      
      #include <QVariant>
      
      class ContractorTask
      {
      public:
          ContractorTask() :
              taskID(-1),
              contractorID(-1),
              data("")
          {}
      
          int getTaskID() { return taskID; }
      
          void setTaskID(int _ID) {taskID = _ID; }
      
          int getConctractorID() { return contractorID; }
      
          void setContractorID(int _ID) { contractorID = _ID; }
      
          QVariant getData() { return data; }
      
          void setData(QVariant _data) { data = _data; }
      
      private:
          int taskID;
          int contractorID;
          QVariant data;
      };
      
      Q_DECLARE_METATYPE(ContractorTask)
      
      #endif // CONTRACTORTASK_H
      
      
      // Controller.h
      
      #ifndef CONTROLLER
      #define CONTROLLER
      
      #include <QObject>
      #include <QThread>
      #include <QDebug>
      
      #include <Contractor.h>
      #include <ContractorTask.h>
      
      class Controller : public QObject
      {
          Q_OBJECT
          QThread workerThread;
      public:
          Controller()
          {
              Contractor *worker = new Contractor(0);
              worker->moveToThread(&workerThread);
      
              connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
      
              connect(this, &Controller::startTask, worker, &Contractor::executeTask);
              connect(worker, &Contractor::taskStarted, this, &Controller::contractorStartedTask);
              connect(worker, &Contractor::taskFinished, this, &Controller::contractorFinishedTask);
              workerThread.start();
          }
      
          ~Controller()
          {
              workerThread.quit();
              workerThread.wait();
          }
      
      signals:
          void startTask(ContractorTask);
          void taskStarted(int id, int contractor, QVariant data);
          void taskEnded(int id, int contractor, QVariant data);
      
      public slots:
          void pushTaskToContractor(int _id, int _contractor, QVariant _data)
          {
              // QVariant depends to QML, so make COPY of QVariant CONTENT, before passing it to thread:
              QList<QVariant> _params;
              _params = _data.value<QList<QVariant>>();
              QVariant _dataToSend = _params;
      
              ContractorTask _taskCopy;
              _taskCopy.setTaskID(_id);
              _taskCopy.setContractorID(_contractor);
              _taskCopy.setData(_dataToSend);                 // Sending local data copy is OK
      
      //        _taskCopy.setData(_data);                     // Sending _data (has source in QML) = PROGRAM CRASH!!!
      
              emit(startTask(_taskCopy));
          }
      
          void contractorFinishedTask(ContractorTask _task)
          {
              // Passing COPY of ContractorTask to QML:
              emit(taskEnded(_task.getTaskID(), _task.getConctractorID(), _task.getData()));
          }
      
          void contractorStartedTask(ContractorTask _task)
          {
              // Passing COPY of ContractorTask to QML:
              emit(taskStarted(_task.getTaskID(), _task.getConctractorID(), _task.getData()));
          }
      };
      
      #endif // CONTROLLER
      
      // main.cpp
      
      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include <Controller.h>
      #include <QQmlContext>
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
      
          QGuiApplication app(argc, argv);
      
          Controller TaskController;
          qRegisterMetaType<ContractorTask>();
      
          QQmlApplicationEngine engine;
          engine.rootContext()->setContextProperty("TaskController", &TaskController);
      
          const QUrl url(QStringLiteral("qrc:/main.qml"));
          QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                           &app, [url](QObject *obj, const QUrl &objUrl) {
              if (!obj && url == objUrl)
                  QCoreApplication::exit(-1);
          }, Qt::QueuedConnection);
          engine.load(url);
      
      
          // Get item from QML, and connect it's signal (startTaskFromQML) to Controller
          QObject *item = engine.rootObjects().first();
          QObject::connect(item, SIGNAL(startTaskFromQML(int, int, QVariant)),
                           &TaskController, SLOT(pushTaskToContractor(int, int, QVariant)));
      
      
          return app.exec();
      }
      
      // main.qml
      
      import QtQuick 2.12
      import QtQuick.Controls 2.5
      
      ApplicationWindow {
          id: root
          visible: true
          width: 640
          height: 480
          title: qsTr("Test")
      
          signal startTaskFromQML(int id, int contractor, variant data)
          property variant _data: 0
      
          Connections {
              target: TaskController
      
              onTaskEnded: console.log("Contractor with ID =", contractor, "finished task with ID = ", id, "and returned result:", data);
      
              onTaskStarted: console.log("Contractor with ID =", contractor, "started task with ID = ", id);
          }
      
          Column {
              id: column
              anchors.horizontalCenter: parent.horizontalCenter
              anchors.verticalCenter: parent.verticalCenter
              Button {
                  id: passAndGet
                  text: qsTr("PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML")
                  anchors.horizontalCenter: parent.horizontalCenter
      
                  onClicked: {
                      _data= [1.2, 3.4, 5.6, 7.8]
      
                      for(var i = 0; i < 50; i++)
                      {
                          root.startTaskFromQML(1, 0, _data)
                      }
                  }
              }
      
              Button {
                  id: getData
                  text: qsTr("PASS TASK TO C++ TO RETRIEVE DATA")
                  anchors.horizontalCenter: parent.horizontalCenter
      
                  onClicked: {
                      _data = 0
                      root.startTaskFromQML(0, 0, _data)
                  }
              }
          }
      }
      
      // qtquickcontrols2.conf
      
      [Controls]
      Style=Material
      
      // qml.qrc
      
      <RCC>
          <qresource prefix="/">
              <file>main.qml</file>
              <file>qtquickcontrols2.conf</file>
          </qresource>
      </RCC>
      
      1 Reply Last reply
      2
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on 20 May 2019, 21:09 last edited by
        #2

        Hi,

        What is the exact goal for that QVariant ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        M 1 Reply Last reply 21 May 2019, 08:47
        0
        • M Matthew11
          20 May 2019, 13:16

          Hi, as topic partially described, I send pointers to my custom type object, which has 3 members (int, int and QVariant) via sig/slot between the main thread and the worker thread. I use the Controller - Worker approach from qt docs.

          Everything was fine when I have two int members in class, and it started crashing (SIGSEGV) since I have added QVariant member to exchange data between QML and C++.

          I'm guessing that crash is caused by accessing the shared resource (my custom class instance). I tried to add some serialization using QMutex, with and without QMutexLocker, QReadWriteLocker but the result was the same - crash. I also tried to protect the shared resource by applying Monitor construct wiki protecting the data with mutexes, but it also didn't work. At the moment I'm out of ideas and look for any help. Thanks in advance.

          Here is my code (plain text and link to git clone), program will probably crash after clicking the button or few spontaneous clicks. ContractorTask is my custom which I want to send using pointers.

          source:

          // ContractorTask.h
          
          #ifndef TASK_H
          #define TASK_H
          
          #include <QObject>
          #include <QVariant>
          #include <QThread>
          #include <QDebug>
          
          class ContractorTask : public QObject
          {
              Q_OBJECT
          
          public:
              explicit ContractorTask(QObject *parent = nullptr) :
                  QObject(parent),
                  taskID(-1),
                  contractorID(-1),
                  data("")
              {
                  // ...
              }
          
              Q_INVOKABLE int getTaskID()
              {
                  qDebug() << "getTaskID()" << QThread::currentThreadId();
                  return taskID;
              }
          
              Q_INVOKABLE void setTaskID(int _ID)
              {
                  qDebug() << "setTaskID()" << QThread::currentThreadId();
                  taskID = _ID;
              }
          
              Q_INVOKABLE int getConctractorID()
              {
                  qDebug() << "getConctractorID()" << QThread::currentThreadId();
                  return contractorID;
              }
          
              Q_INVOKABLE void setContractorID(int _ID)
              {
                  qDebug() << "setContractorID()" << QThread::currentThreadId();
                  contractorID = _ID;
              }
          
              Q_INVOKABLE QVariant getData()
              {
                  qDebug() << "getData()" << QThread::currentThreadId();
                  return data;
              }
          
              Q_INVOKABLE void setData(QVariant _data)
              {
                  qDebug() << "setData()" << QThread::currentThreadId();
                  data = _data;
              }
          
          private:
              int taskID;
              int contractorID;
              QVariant data;
          };
          
          #endif // TASK_H
          
          // Contractor.h
          
          #ifndef CONTRACTOR_H
          #define CONTRACTOR_H
          
          #include <QObject>
          #include <QQmlEngine>
          #include <QThread>
          #include <QMutex>
          
          #include <ContractorTask.h>
          
          //#define CONTRACTOR_DEBUG_LOCK
          
          class Contractor : public QObject
          {
              Q_OBJECT
          
          public:
              Contractor(int _ID, QObject* parent = nullptr);
              ~Contractor();
          
              enum class Tasks : int
              {
                  NOT_DEFINED = -1,
                  Q_LIST_VARIANTS_TO_QML,
                  GET_QVARIANT_FROM_QML
              };
          
              Q_ENUMS(Tasks)
          
              inline static void registerTasks()
              {
                  qmlRegisterUncreatableType<Contractor>("Tasks", 1, 0, "ContractorTasks", "ContractorTask is uncreatable in QML");
              }
          
              int getID()
              {
                  return ID;
              }
          
          public slots:
              void executeTask(ContractorTask* _task);
          
          signals:
              void finished();
              void taskStarted(ContractorTask* _task);
              void taskFinished(ContractorTask* _task);
          
          private:
              int ID;
          
          #ifndef CONTRACTOR_DEBUG_LOCK
              Qt::HANDLE mainThreadID;
          #endif
          };
          #endif // CONTRACTOR_H
          
          //Contractor.cpp
          
          #include "Contractor.h"
          
          #include <QDebug>
          #include <QThread>
          
          Contractor::Contractor(int _ID, QObject *parent) :
              QObject(parent),
              ID(_ID)
          {
          #ifndef CONTRACTOR_DEBUG_LOCK
              mainThreadID = QThread::currentThreadId();
          #endif
          }
          
          Contractor::~Contractor()
          {
              // ...
          
              qDebug() << "Cleaning SerialPortContractor...";
          }
          
          void Contractor::executeTask(ContractorTask* _task)
          {
              emit(taskStarted(_task));
          
              qDebug() << "\tCONTRACTOR STARTED";
          
              int localContractorID = _task->getConctractorID();
          
              if(localContractorID != getID())
              {
                  qDebug() << "Not mine ID: " << localContractorID << "discarding";
                  return;
              }
          
              qDebug() << "Emiting signal from Contractor";
              emit(taskStarted(_task));
          
              int localTaskID = _task->getTaskID();
              QVariant localData = _task->getData();
          
              QList<QVariant> _params;
              QList<float> _floats;
              _params = localData.value<QList<QVariant>>();
          
              for(auto item : _params)
              {
                  _floats << item.toFloat();
              }
          
          #ifndef CONTRACTOR_DEBUG_LOCK
              qDebug() << "Main ThreadID =" << mainThreadID << "my ThreadID =" << QThread::currentThreadId();
          #endif
          
              switch(static_cast<Tasks>(localTaskID))
              {
              case Tasks::Q_LIST_VARIANTS_TO_QML :
              {
                  QList<QVariant> _params;
                  _params.append(12.5F);
                  _params.append(14.36F);
          
                  QVariant _data = _params;
          
                  _task->setData(_data);
              }
                  break;
              case Tasks::GET_QVARIANT_FROM_QML:
              {
                  int i = 0;
                  for(auto item : _floats)
                  {
                      qDebug() << "C++ item" << i++ << "value" << item;
                  }
              }
                  break;
              default:
              {
          #ifndef CONTRACTOR_DEBUG_LOCK
                  qDebug() << "Oh... I don't have these one :(";
          #endif
              }
              }
          
              emit(taskFinished(_task));
          
              qDebug() << "\tCONTRACTOR ENDED";
          }
          
          // Controller.h
          
          #ifndef CONTROLLERv2_H
          #define CONTROLLERv2_H
          
          #include <QObject>
          #include <QThread>
          #include <QDebug>
          
          #include <Contractor.h>
          #include <ContractorTask.h>
          
          class Controller : public QObject
          {
              Q_OBJECT
              QThread workerThread;
          
          public:
              Controller()
              {
                  Contractor *worker = new Contractor(0);
                  worker->moveToThread(&workerThread);
                  connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
                  connect(this, &Controller::startTask, worker, &Contractor::executeTask);
                  connect(worker, &Contractor::taskFinished, this, &Controller::handleResults);
                  workerThread.start();
              }
          
              ~Controller()
              {
                  workerThread.quit();
                  workerThread.wait();
              }
          
          signals:
              void startTask(ContractorTask*);
          
          public slots:
              void handleResults(ContractorTask* _task)
              {
                  qDebug() << _task->getTaskID() << _task->getConctractorID() << _task->getData();
              }
          };
          #endif // CONTROLLERv2_H
          
          // main.cpp
          
          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          #include <Controller.h>
          #include <QQmlContext>
          
          int main(int argc, char *argv[])
          {
              QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
          
              QGuiApplication app(argc, argv);
          
              Contractor::registerTasks();
              Controller TaskController;
              ContractorTask Task;
          
              QQmlApplicationEngine engine;
              engine.rootContext()->setContextProperty("TaskController", &TaskController);
              engine.rootContext()->setContextProperty("Task", &Task);
          
              const QUrl url(QStringLiteral("qrc:/main.qml"));
              QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                               &app, [url](QObject *obj, const QUrl &objUrl) {
                  if (!obj && url == objUrl)
                      QCoreApplication::exit(-1);
              }, Qt::QueuedConnection);
              engine.load(url);
          
              return app.exec();
          }
          
          // main.qml
          
          import QtQuick 2.12
          import QtQuick.Controls 2.5
          
          import Tasks 1.0
          
          ApplicationWindow {
              id: applicationWindow
              visible: true
              width: 640
              height: 480
              title: qsTr("Test")
          
              Button {
                  id: button
                  text: qsTr("Button")
                  anchors.verticalCenter: parent.verticalCenter
                  anchors.horizontalCenter: parent.horizontalCenter
          
                  onClicked: {
                      var items = [1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2, 1.25, 2.12345, 2.2]
          
                      Task.setData(items)
                      runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                      runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                      runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                      runTaskFromQML(ContractorTasks.GET_QVARIANT_FROM_QML, 0)
                  }
              }
          
              function runTaskFromQML(_taskId, _contractorID)
              {
                  console.log("Running worker task from QML, ID = ", _taskId, " Contractor ID = ", _contractorID)
          
                  Task.setTaskID(_taskId)
                  Task.setContractorID(_contractorID)
                  TaskController.startTask(Task)
              }
          }
          
          // .pro
          
          QT += quick
          CONFIG += c++11
          
          DEFINES += QT_DEPRECATED_WARNINGS
          
          SOURCES += \
                  Contractor.cpp \
                  main.cpp
          
          RESOURCES += qml.qrc
          
          # Default rules for deployment.
          qnx: target.path = /tmp/$${TARGET}/bin
          else: unix:!android: target.path = /opt/$${TARGET}/bin
          !isEmpty(target.path): INSTALLS += target
          
          HEADERS += \
              Contractor.h \
              ContractorTask.h \
              Controller.h
          
          K Offline
          K Offline
          kshegunov
          Moderators
          wrote on 20 May 2019, 21:40 last edited by
          #3

          @Matthew11 said in Passing custom type pointers between threads via signals and slots cause app to crash:

          I'm guessing that crash is caused by accessing the shared resource (my custom class instance). I tried to add some serialization using QMutex, with and without QMutexLocker, QReadWriteLocker but the result was the same - crash.

          Crashes have stack traces. Please provide one. Also as a hint:

          Q_INVOKABLE void setData(QVariant _data)
          {
              Q_ASSERT(QThread::currentThread() == thread());
          
              qDebug() << "setData()" << QThread::currentThreadId();
              data = _data;
          }
          

          Read and abide by the Qt Code of Conduct

          M 1 Reply Last reply 21 May 2019, 09:39
          3
          • SGaistS SGaist
            20 May 2019, 21:09

            Hi,

            What is the exact goal for that QVariant ?

            M Offline
            M Offline
            Matthew11
            wrote on 21 May 2019, 08:47 last edited by
            #4

            @SGaist said in Passing custom type pointers between threads via signals and slots cause app to crash:

            What is the exact goal for that QVariant ?

            Well, simply speaking, to pass various data between QML and C++ (floats, integers, QStrings and any that will be needed) within the ContractorTask object.

            Use of case: The UI send request (with taskID, contractorID (both ints) and data (QVariant) as ContractorTask object) then the specific Contractor (another thread) run specific code and return the result (QVariant) which is also included in ContractorTask object. Then in QML, I know which task was started and ended and with what data -> the UI can be updated. As well in the opposite direction (C++ received event, then sends data to QML). I also have interfaces (not included in the sources that I provided) for Contractor and Controller which relay on ContractorTask object and simplifies things with making new Contractors passing them to Controller which takes care of connections, clean up (things that Controller does).

            1 Reply Last reply
            0
            • K kshegunov
              20 May 2019, 21:40

              @Matthew11 said in Passing custom type pointers between threads via signals and slots cause app to crash:

              I'm guessing that crash is caused by accessing the shared resource (my custom class instance). I tried to add some serialization using QMutex, with and without QMutexLocker, QReadWriteLocker but the result was the same - crash.

              Crashes have stack traces. Please provide one. Also as a hint:

              Q_INVOKABLE void setData(QVariant _data)
              {
                  Q_ASSERT(QThread::currentThread() == thread());
              
                  qDebug() << "setData()" << QThread::currentThreadId();
                  data = _data;
              }
              
              M Offline
              M Offline
              Matthew11
              wrote on 21 May 2019, 09:39 last edited by Matthew11
              #5

              @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

              Crashes have stack traces. Please provide one. Also as a hint:
              Q_ASSERT(QThread::currentThread() == thread());

              So, If I understand it correctly, it gives me insights where and when another thread is working on resources from another thread? So it happens when Contractor is working on _task in Contractor::executeTask(ContractorTask*) which is "normal" in this case. And these places should be protected. Am I right, that's the hint?

              Returning to stack traces, I generated them for the same code included before. App crashes seem to be connected with QV4Object. 3'rd and 6'th seem to be more common. Is the table content enough or will it be better with screenshots?

              -->1<--
              
              1   QV4::Object::get                           qv4object_p.h                308  0x7ffff714c2fc 
              2   QV4::Runtime::method_callProperty          qv4runtime.cpp               1376 0x7ffff714c2fc 
              3   QV4::Moth::VME::interpret                  qv4vme_moth.cpp              718  0x7ffff70e3f90 
              4   QV4::Moth::VME::exec                       qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              5   QV4::ArrowFunction::virtualCall            qv4functionobject.cpp        513  0x7ffff7080720 
              6   QV4::FunctionObject::call                  qv4functionobject_p.h        202  0x7ffff71474a3 
              7   QV4::Runtime::method_callName              qv4runtime.cpp               1346 0x7ffff71474a3 
              8   QV4::Moth::VME::interpret                  qv4vme_moth.cpp              745  0x7ffff70e3e37 
              9   QV4::Moth::VME::exec                       qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              10  QV4::Function::call                        qv4function.cpp              68   0x7ffff707fade 
              11  QQmlJavaScriptExpression::evaluate         qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
              12  QQmlBoundSignalExpression::evaluate        qqmlboundsignal.cpp          225  0x7ffff718aa52 
              13  QQmlBoundSignal_callback                   qqmlboundsignal.cpp          358  0x7ffff718bf53 
              14  QQmlNotifier::emitNotify                   qqmlnotifier.cpp             106  0x7ffff71c9cf4 
              15  QQmlData::signalEmitted                    qqmlengine.cpp               880  0x7ffff716e274 
              16  QMetaObject::activate                      qobject.cpp                  3648 0x7ffff6a20c92 
              17  QQuickAbstractButtonPrivate::handleRelease qquickabstractbutton.cpp     179  0x7fffd0d71ca8 
              18  QQuickControl::mouseReleaseEvent           qquickcontrol.cpp            2099 0x7fffd0d8c9f5 
              19  QQuickItem::event                          qquickitem.cpp               8096 0x7fffd22c98de 
              20  QCoreApplication::notifyInternal2          qcoreapplication.cpp         1061 0x7ffff69f4c18         
              
              --> 2 <--
              
              1   QV4::IdentifierHash::lookup         qv4identifier.cpp            173  0x7ffff7058c28 
              2   QV4::IdentifierHash::value          qv4identifier_p.h            165  0x7ffff70a6bc5 
              3   QV4::QQmlContextWrapper::virtualGet qv4qmlcontext.cpp            196  0x7ffff70a6bc5 
              4   QV4::Object::get                    qv4object_p.h                314  0x7ffff7055b65 
              5   QV4::ExecutionContext::getProperty  qv4context.cpp               360  0x7ffff7055b65 
              6   QV4::Runtime::method_loadName       qv4runtime.cpp               985  0x7ffff7143df0 
              7   QV4::Moth::VME::interpret           qv4vme_moth.cpp              548  0x7ffff70e413e 
              8   QV4::Moth::VME::exec                qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              9   QV4::ArrowFunction::virtualCall     qv4functionobject.cpp        513  0x7ffff7080720 
              10  QV4::FunctionObject::call           qv4functionobject_p.h        202  0x7ffff71474a3 
              11  QV4::Runtime::method_callName       qv4runtime.cpp               1346 0x7ffff71474a3 
              12  QV4::Moth::VME::interpret           qv4vme_moth.cpp              745  0x7ffff70e3e37 
              13  QV4::Moth::VME::exec                qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              14  QV4::Function::call                 qv4function.cpp              68   0x7ffff707fade 
              15  QQmlJavaScriptExpression::evaluate  qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
              16  QQmlBoundSignalExpression::evaluate qqmlboundsignal.cpp          225  0x7ffff718aa52 
              17  QQmlBoundSignal_callback            qqmlboundsignal.cpp          358  0x7ffff718bf53 
              18  QQmlNotifier::emitNotify            qqmlnotifier.cpp             106  0x7ffff71c9cf4 
              19  QQmlData::signalEmitted             qqmlengine.cpp               880  0x7ffff716e274 
              20  QMetaObject::activate               qobject.cpp                  3648 0x7ffff6a20c92 
              
              --> 3 <--
              
              1  QV4::Heap::String::append                        qv4string.cpp                235  0x7ffff714dcdc 
              2  QV4::Heap::String::simplifyString                qv4string.cpp                184  0x7ffff714de22 
              3  QV4::String::createPropertyKeyImpl               qv4string.cpp                172  0x7ffff714dfcb 
              4  QV4::StringOrSymbol::createPropertyKey           qv4string_p.h                311  0x7ffff714c324 
              5  QV4::StringOrSymbol::toPropertyKey               qv4string_p.h                316  0x7ffff714c324 
              6  QV4::Object::get                                 qv4object_p.h                308  0x7ffff714c324 
              7  QV4::Runtime::method_callProperty                qv4runtime.cpp               1376 0x7ffff714c324 
              8  QV4::Moth::VME::interpret                        qv4vme_moth.cpp              718  0x7ffff70e3f90 
              9  QV4::Moth::VME::exec                             qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              10 QV4::ArrowFunction::virtualCall                  qv4functionobject.cpp        513  0x7ffff7080720 
              11 QV4::FunctionObject::call                        qv4functionobject_p.h        202  0x7ffff71474a3 
              12 QV4::Runtime::method_callName                    qv4runtime.cpp               1346 0x7ffff71474a3 
              13 QV4::Moth::VME::interpret                        qv4vme_moth.cpp              745  0x7ffff70e3e37 
              14 QV4::Moth::VME::exec                             qv4vme_moth.cpp              441  0x7ffff70e7cc4 
              15 QV4::Function::call                              qv4function.cpp              68   0x7ffff707fade 
              16 QQmlJavaScriptExpression::evaluate               qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
              17 QQmlBoundSignalExpression::evaluate              qqmlboundsignal.cpp          225  0x7ffff718aa52 
              18 QQmlBoundSignal_callback                         qqmlboundsignal.cpp          358  0x7ffff718bf53 
              19 QQmlNotifier::emitNotify                         qqmlnotifier.cpp             106  0x7ffff71c9cf4 
              20 QQmlData::signalEmitted                          qqmlengine.cpp               880  0x7ffff716e274 
              21 QMetaObject::activate                            qobject.cpp                  3648 0x7ffff6a20c92 
              22 QQuickAbstractButtonPrivate::handleRelease       qquickabstractbutton.cpp     179  0x7fffd0d71ca8 
              23 QQuickControl::mouseReleaseEvent                 qquickcontrol.cpp            2099 0x7fffd0d8c9f5 
              24 QQuickItem::event                                qquickitem.cpp               8096 0x7fffd22c98de 
              25 QCoreApplication::notifyInternal2                qcoreapplication.cpp         1061 0x7ffff69f4c18 
              26 QCoreApplication::sendEvent                      qcoreapplication.cpp         1451 0x7ffff69f4dce 
              27 QQuickWindowPrivate::deliverMouseEvent           qquickwindow.cpp             1784 0x7fffd22e23bf 
              28 QQuickWindowPrivate::deliverPointerEvent         qquickwindow.cpp             2346 0x7fffd22e36fb 
              29 QQuickWindowPrivate::handleMouseEvent            qquickwindow.cpp             2210 0x7fffd22e4535 
              30 QWindow::event                                   qwindow.cpp                  2336 0x7ffff77044eb 
              31 QQuickWindow::event                              qquickwindow.cpp             1673 0x7fffd22e54e5 
              32 QCoreApplication::notifyInternal2                qcoreapplication.cpp         1061 0x7ffff69f4c18 
              33 QCoreApplication::sendSpontaneousEvent           qcoreapplication.cpp         1463 0x7ffff69f4dde 
              34 QGuiApplicationPrivate::processMouseEvent        qguiapplication.cpp          2102 0x7ffff76f91e7 
              35 QGuiApplicationPrivate::processWindowSystemEvent qguiapplication.cpp          1837 0x7ffff76fa795 
              36 QWindowSystemInterface::sendWindowSystemEvents   qwindowsysteminterface.cpp   1068 0x7ffff76d644b 
              37 xcbSourceDispatch                                qxcbeventdispatcher.cpp      105  0x7ffff014767a 
              38 g_main_context_dispatch                                                            0x7ffff24dc417 
              39 ??                                                                                 0x7ffff24dc650 
              40 g_main_context_iteration                                                           0x7ffff24dc6dc 
              41 QEventDispatcherGlib::processEvents              qeventdispatcher_glib.cpp    422  0x7ffff6a4bdcf 
              42 QEventLoop::exec                                 qeventloop.cpp               225  0x7ffff69f357a 
              43 QCoreApplication::exec                           qcoreapplication.cpp         1364 0x7ffff69fbf80 
              44 main                                             main.cpp                     28   0x55555555be66 
              
              --> 4 <--
              
              
              1  QV4::Object::get                                                                                                                          qv4object_p.h             310  0x7ffff713cee4 
              2  objectToVariant                                                                                                                           qv4engine.cpp             1389 0x7ffff713cee4 
              3  toVariant                                                                                                                                 qv4engine.cpp             1359 0x7ffff713d949 
              4  QV4::ExecutionEngine::toVariant                                                                                                           qv4engine.cpp             1252 0x7ffff713dc10 
              5  QJSValue::toVariant                                                                                                                       qjsvalue.cpp              714  0x7ffff70521e4 
              6  convertJSValueToVariantType<QList<QVariant>>                                                                                              qv8engine.cpp             100  0x7ffff721b4c1 
              7  QtPrivate::ConverterFunctor<QJSValue, QList<QVariant>, QList<QVariant> ( *)(QJSValue const&)>::convert                                    qmetatype.h               398  0x7ffff721b162 
              8  QMetaType::convert                                                                                                                        qmetatype.cpp             739  0x7ffff6a0b36d 
              9  (anonymous namespace)::convert                                                                                                            qvariant.cpp              393  0x7ffff6a3ada1 
              10 QtPrivate::QVariantValueHelper<QList<QVariant>>::metaType                                                                                 qvariant.h                725  0x55555555a42e 
              11 QtPrivate::MetaTypeInvoker<QtPrivate::QVariantValueHelper<QList<QVariant>>, QVariant const&, QList<QVariant>>::invoke                     qvariant.h                115  0x5555555594c7 
              12 QtPrivate::QVariantValueHelperInterface<QList<QVariant>>::invoke                                                                          qvariant.h                793  0x5555555589f0 
              13 qvariant_cast<QList<QVariant>>                                                                                                            qvariant.h                860  0x55555555a536 
              14 QVariant::value<QList<QVariant>>                                                                                                          qvariant.h                362  0x555555559576 
              15 Contractor::executeTask                                                                                                                   Contractor.cpp            44   0x555555557a9a 
              16 QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<ContractorTask *>, void, void (Contractor:: *)(ContractorTask *)>::call qobjectdefs_impl.h        152  0x55555555e49b 
              17 QtPrivate::FunctionPointer<void (Contractor:: *)(ContractorTask *)>::call<QtPrivate::List<ContractorTask *>, void>                        qobjectdefs_impl.h        185  0x55555555e179 
              18 QtPrivate::QSlotObject<void (Contractor:: *)(ContractorTask *), QtPrivate::List<ContractorTask *>, void>::impl                            qobjectdefs_impl.h        414  0x55555555de01 
              19 QObject::event                                                                                                                            qobject.cpp               1249 0x7ffff6a21581 
              20 QCoreApplication::notifyInternal2                                                                                                         qcoreapplication.cpp      1061 0x7ffff69f4c18 
              21 QCoreApplication::sendEvent                                                                                                               qcoreapplication.cpp      1451 0x7ffff69f4dce 
              22 QCoreApplicationPrivate::sendPostedEvents                                                                                                 qcoreapplication.cpp      1800 0x7ffff69f7647 
              23 QCoreApplication::sendPostedEvents                                                                                                        qcoreapplication.cpp      1654 0x7ffff69f7b28 
              24 postEventSourceDispatch                                                                                                                   qeventdispatcher_glib.cpp 276  0x7ffff6a4c793 
              25 g_main_context_dispatch                                                                                                                                                  0x7ffff24dc417 
              26 ??                                                                                                                                                                       0x7ffff24dc650 
              27 g_main_context_iteration                                                                                                                                                 0x7ffff24dc6dc 
              28 QEventDispatcherGlib::processEvents                                                                                                       qeventdispatcher_glib.cpp 422  0x7ffff6a4bdcf 
              29 QEventLoop::exec                                                                                                                          qeventloop.cpp            225  0x7ffff69f357a 
              30 QThread::exec                                                                                                                             qthread.cpp               531  0x7ffff682b7dc 
              31 QThreadPrivate::start                                                                                                                     qthread_unix.cpp          361  0x7ffff682cd13 
              32 start_thread                                                                                                                              pthread_create.c          463  0x7ffff5bdd6db 
              33 clone                                                                                                                                     clone.S                   95   0x7ffff5f1688f                                            
              
              --> 5 <--
              
              1   QV4::Object::ownPropertyKeys                                                                                                              qv4object_p.h         367  0x7ffff713cbdd 
              2   QV4::ObjectIterator::ObjectIterator                                                                                                       qv4objectiterator_p.h 80   0x7ffff713cbdd 
              3   objectToVariant                                                                                                                           qv4engine.cpp         1397 0x7ffff713cbdd 
              4   toVariant                                                                                                                                 qv4engine.cpp         1359 0x7ffff713d949 
              5   QV4::ExecutionEngine::toVariant                                                                                                           qv4engine.cpp         1252 0x7ffff713dc10 
              6   QJSValue::toVariant                                                                                                                       qjsvalue.cpp          714  0x7ffff70521e4 
              7   convertJSValueToVariantType<QList<QVariant>>                                                                                              qv8engine.cpp         100  0x7ffff721b4c1 
              8   QtPrivate::ConverterFunctor<QJSValue, QList<QVariant>, QList<QVariant> ( *)(QJSValue const&)>::convert                                    qmetatype.h           398  0x7ffff721b162 
              9   QMetaType::convert                                                                                                                        qmetatype.cpp         739  0x7ffff6a0b36d 
              10  (anonymous namespace)::convert                                                                                                            qvariant.cpp          393  0x7ffff6a3ada1 
              11  QtPrivate::QVariantValueHelper<QList<QVariant>>::metaType                                                                                 qvariant.h            725  0x55555555a42e 
              12  QtPrivate::MetaTypeInvoker<QtPrivate::QVariantValueHelper<QList<QVariant>>, QVariant const&, QList<QVariant>>::invoke                     qvariant.h            115  0x5555555594c7 
              13  QtPrivate::QVariantValueHelperInterface<QList<QVariant>>::invoke                                                                          qvariant.h            793  0x5555555589f0 
              14  qvariant_cast<QList<QVariant>>                                                                                                            qvariant.h            860  0x55555555a536 
              15  QVariant::value<QList<QVariant>>                                                                                                          qvariant.h            362  0x555555559576 
              16  Contractor::executeTask                                                                                                                   Contractor.cpp        44   0x555555557a9a 
              17  QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<ContractorTask *>, void, void (Contractor:: *)(ContractorTask *)>::call qobjectdefs_impl.h    152  0x55555555e49b 
              18  QtPrivate::FunctionPointer<void (Contractor:: *)(ContractorTask *)>::call<QtPrivate::List<ContractorTask *>, void>                        qobjectdefs_impl.h    185  0x55555555e179 
              19  QtPrivate::QSlotObject<void (Contractor:: *)(ContractorTask *), QtPrivate::List<ContractorTask *>, void>::impl                            qobjectdefs_impl.h    414  0x55555555de01 
              20  QObject::event                                                                                                                            qobject.cpp           1249 0x7ffff6a21581 
              ... <More>                                                                                                                                                                              
              
              --> 6 <--
              
              1   QV4::Heap::String::append                  qv4string.cpp         235  0x7ffff714dcdc 
              2   QV4::Heap::String::simplifyString          qv4string.cpp         184  0x7ffff714de22 
              3   QV4::Heap::StringOrSymbol::createHashValue qv4string.cpp         245  0x7ffff714e185 
              4   QV4::Heap::StringOrSymbol::hashValue       qv4string_p.h         97   0x7ffff70ceb35 
              5   QV4::Heap::String::isEqualTo               qv4string_p.h         128  0x7ffff70ceb35 
              6   QV4::String::equals                        qv4string_p.h         203  0x7ffff70cb3db 
              7   QV4::QObjectWrapper::getQmlProperty        qv4qobjectwrapper.cpp 283  0x7ffff70cb3db 
              8   QV4::QObjectWrapper::getQmlProperty        qv4qobjectwrapper.cpp 414  0x7ffff70cbc4e 
              9   QV4::QQmlContextWrapper::virtualGet        qv4qmlcontext.cpp     246  0x7ffff70a6c66 
              10  QV4::Object::get                           qv4object_p.h         314  0x7ffff7055b65 
              11  QV4::ExecutionContext::getProperty         qv4context.cpp        360  0x7ffff7055b65 
              12  QV4::Runtime::method_loadName              qv4runtime.cpp        985  0x7ffff7143df0 
              13  QV4::Moth::VME::interpret                  qv4vme_moth.cpp       548  0x7ffff70e413e 
              14  QV4::Moth::VME::exec                       qv4vme_moth.cpp       441  0x7ffff70e7cc4 
              15  QV4::ArrowFunction::virtualCall            qv4functionobject.cpp 513  0x7ffff7080720 
              16  QV4::FunctionObject::call                  qv4functionobject_p.h 202  0x7ffff71474a3 
              17  QV4::Runtime::method_callName              qv4runtime.cpp        1346 0x7ffff71474a3 
              18  QV4::Moth::VME::interpret                  qv4vme_moth.cpp       745  0x7ffff70e3e37 
              19  QV4::Moth::VME::exec                       qv4vme_moth.cpp       441  0x7ffff70e7cc4 
              20  QV4::Function::call                        qv4function.cpp       68   0x7ffff707fade 
              ... <More>                                                                               
              
              
              K 1 Reply Last reply 21 May 2019, 19:13
              0
              • M Matthew11
                21 May 2019, 09:39

                @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

                Crashes have stack traces. Please provide one. Also as a hint:
                Q_ASSERT(QThread::currentThread() == thread());

                So, If I understand it correctly, it gives me insights where and when another thread is working on resources from another thread? So it happens when Contractor is working on _task in Contractor::executeTask(ContractorTask*) which is "normal" in this case. And these places should be protected. Am I right, that's the hint?

                Returning to stack traces, I generated them for the same code included before. App crashes seem to be connected with QV4Object. 3'rd and 6'th seem to be more common. Is the table content enough or will it be better with screenshots?

                -->1<--
                
                1   QV4::Object::get                           qv4object_p.h                308  0x7ffff714c2fc 
                2   QV4::Runtime::method_callProperty          qv4runtime.cpp               1376 0x7ffff714c2fc 
                3   QV4::Moth::VME::interpret                  qv4vme_moth.cpp              718  0x7ffff70e3f90 
                4   QV4::Moth::VME::exec                       qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                5   QV4::ArrowFunction::virtualCall            qv4functionobject.cpp        513  0x7ffff7080720 
                6   QV4::FunctionObject::call                  qv4functionobject_p.h        202  0x7ffff71474a3 
                7   QV4::Runtime::method_callName              qv4runtime.cpp               1346 0x7ffff71474a3 
                8   QV4::Moth::VME::interpret                  qv4vme_moth.cpp              745  0x7ffff70e3e37 
                9   QV4::Moth::VME::exec                       qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                10  QV4::Function::call                        qv4function.cpp              68   0x7ffff707fade 
                11  QQmlJavaScriptExpression::evaluate         qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
                12  QQmlBoundSignalExpression::evaluate        qqmlboundsignal.cpp          225  0x7ffff718aa52 
                13  QQmlBoundSignal_callback                   qqmlboundsignal.cpp          358  0x7ffff718bf53 
                14  QQmlNotifier::emitNotify                   qqmlnotifier.cpp             106  0x7ffff71c9cf4 
                15  QQmlData::signalEmitted                    qqmlengine.cpp               880  0x7ffff716e274 
                16  QMetaObject::activate                      qobject.cpp                  3648 0x7ffff6a20c92 
                17  QQuickAbstractButtonPrivate::handleRelease qquickabstractbutton.cpp     179  0x7fffd0d71ca8 
                18  QQuickControl::mouseReleaseEvent           qquickcontrol.cpp            2099 0x7fffd0d8c9f5 
                19  QQuickItem::event                          qquickitem.cpp               8096 0x7fffd22c98de 
                20  QCoreApplication::notifyInternal2          qcoreapplication.cpp         1061 0x7ffff69f4c18         
                
                --> 2 <--
                
                1   QV4::IdentifierHash::lookup         qv4identifier.cpp            173  0x7ffff7058c28 
                2   QV4::IdentifierHash::value          qv4identifier_p.h            165  0x7ffff70a6bc5 
                3   QV4::QQmlContextWrapper::virtualGet qv4qmlcontext.cpp            196  0x7ffff70a6bc5 
                4   QV4::Object::get                    qv4object_p.h                314  0x7ffff7055b65 
                5   QV4::ExecutionContext::getProperty  qv4context.cpp               360  0x7ffff7055b65 
                6   QV4::Runtime::method_loadName       qv4runtime.cpp               985  0x7ffff7143df0 
                7   QV4::Moth::VME::interpret           qv4vme_moth.cpp              548  0x7ffff70e413e 
                8   QV4::Moth::VME::exec                qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                9   QV4::ArrowFunction::virtualCall     qv4functionobject.cpp        513  0x7ffff7080720 
                10  QV4::FunctionObject::call           qv4functionobject_p.h        202  0x7ffff71474a3 
                11  QV4::Runtime::method_callName       qv4runtime.cpp               1346 0x7ffff71474a3 
                12  QV4::Moth::VME::interpret           qv4vme_moth.cpp              745  0x7ffff70e3e37 
                13  QV4::Moth::VME::exec                qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                14  QV4::Function::call                 qv4function.cpp              68   0x7ffff707fade 
                15  QQmlJavaScriptExpression::evaluate  qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
                16  QQmlBoundSignalExpression::evaluate qqmlboundsignal.cpp          225  0x7ffff718aa52 
                17  QQmlBoundSignal_callback            qqmlboundsignal.cpp          358  0x7ffff718bf53 
                18  QQmlNotifier::emitNotify            qqmlnotifier.cpp             106  0x7ffff71c9cf4 
                19  QQmlData::signalEmitted             qqmlengine.cpp               880  0x7ffff716e274 
                20  QMetaObject::activate               qobject.cpp                  3648 0x7ffff6a20c92 
                
                --> 3 <--
                
                1  QV4::Heap::String::append                        qv4string.cpp                235  0x7ffff714dcdc 
                2  QV4::Heap::String::simplifyString                qv4string.cpp                184  0x7ffff714de22 
                3  QV4::String::createPropertyKeyImpl               qv4string.cpp                172  0x7ffff714dfcb 
                4  QV4::StringOrSymbol::createPropertyKey           qv4string_p.h                311  0x7ffff714c324 
                5  QV4::StringOrSymbol::toPropertyKey               qv4string_p.h                316  0x7ffff714c324 
                6  QV4::Object::get                                 qv4object_p.h                308  0x7ffff714c324 
                7  QV4::Runtime::method_callProperty                qv4runtime.cpp               1376 0x7ffff714c324 
                8  QV4::Moth::VME::interpret                        qv4vme_moth.cpp              718  0x7ffff70e3f90 
                9  QV4::Moth::VME::exec                             qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                10 QV4::ArrowFunction::virtualCall                  qv4functionobject.cpp        513  0x7ffff7080720 
                11 QV4::FunctionObject::call                        qv4functionobject_p.h        202  0x7ffff71474a3 
                12 QV4::Runtime::method_callName                    qv4runtime.cpp               1346 0x7ffff71474a3 
                13 QV4::Moth::VME::interpret                        qv4vme_moth.cpp              745  0x7ffff70e3e37 
                14 QV4::Moth::VME::exec                             qv4vme_moth.cpp              441  0x7ffff70e7cc4 
                15 QV4::Function::call                              qv4function.cpp              68   0x7ffff707fade 
                16 QQmlJavaScriptExpression::evaluate               qqmljavascriptexpression.cpp 216  0x7ffff71e7eb8 
                17 QQmlBoundSignalExpression::evaluate              qqmlboundsignal.cpp          225  0x7ffff718aa52 
                18 QQmlBoundSignal_callback                         qqmlboundsignal.cpp          358  0x7ffff718bf53 
                19 QQmlNotifier::emitNotify                         qqmlnotifier.cpp             106  0x7ffff71c9cf4 
                20 QQmlData::signalEmitted                          qqmlengine.cpp               880  0x7ffff716e274 
                21 QMetaObject::activate                            qobject.cpp                  3648 0x7ffff6a20c92 
                22 QQuickAbstractButtonPrivate::handleRelease       qquickabstractbutton.cpp     179  0x7fffd0d71ca8 
                23 QQuickControl::mouseReleaseEvent                 qquickcontrol.cpp            2099 0x7fffd0d8c9f5 
                24 QQuickItem::event                                qquickitem.cpp               8096 0x7fffd22c98de 
                25 QCoreApplication::notifyInternal2                qcoreapplication.cpp         1061 0x7ffff69f4c18 
                26 QCoreApplication::sendEvent                      qcoreapplication.cpp         1451 0x7ffff69f4dce 
                27 QQuickWindowPrivate::deliverMouseEvent           qquickwindow.cpp             1784 0x7fffd22e23bf 
                28 QQuickWindowPrivate::deliverPointerEvent         qquickwindow.cpp             2346 0x7fffd22e36fb 
                29 QQuickWindowPrivate::handleMouseEvent            qquickwindow.cpp             2210 0x7fffd22e4535 
                30 QWindow::event                                   qwindow.cpp                  2336 0x7ffff77044eb 
                31 QQuickWindow::event                              qquickwindow.cpp             1673 0x7fffd22e54e5 
                32 QCoreApplication::notifyInternal2                qcoreapplication.cpp         1061 0x7ffff69f4c18 
                33 QCoreApplication::sendSpontaneousEvent           qcoreapplication.cpp         1463 0x7ffff69f4dde 
                34 QGuiApplicationPrivate::processMouseEvent        qguiapplication.cpp          2102 0x7ffff76f91e7 
                35 QGuiApplicationPrivate::processWindowSystemEvent qguiapplication.cpp          1837 0x7ffff76fa795 
                36 QWindowSystemInterface::sendWindowSystemEvents   qwindowsysteminterface.cpp   1068 0x7ffff76d644b 
                37 xcbSourceDispatch                                qxcbeventdispatcher.cpp      105  0x7ffff014767a 
                38 g_main_context_dispatch                                                            0x7ffff24dc417 
                39 ??                                                                                 0x7ffff24dc650 
                40 g_main_context_iteration                                                           0x7ffff24dc6dc 
                41 QEventDispatcherGlib::processEvents              qeventdispatcher_glib.cpp    422  0x7ffff6a4bdcf 
                42 QEventLoop::exec                                 qeventloop.cpp               225  0x7ffff69f357a 
                43 QCoreApplication::exec                           qcoreapplication.cpp         1364 0x7ffff69fbf80 
                44 main                                             main.cpp                     28   0x55555555be66 
                
                --> 4 <--
                
                
                1  QV4::Object::get                                                                                                                          qv4object_p.h             310  0x7ffff713cee4 
                2  objectToVariant                                                                                                                           qv4engine.cpp             1389 0x7ffff713cee4 
                3  toVariant                                                                                                                                 qv4engine.cpp             1359 0x7ffff713d949 
                4  QV4::ExecutionEngine::toVariant                                                                                                           qv4engine.cpp             1252 0x7ffff713dc10 
                5  QJSValue::toVariant                                                                                                                       qjsvalue.cpp              714  0x7ffff70521e4 
                6  convertJSValueToVariantType<QList<QVariant>>                                                                                              qv8engine.cpp             100  0x7ffff721b4c1 
                7  QtPrivate::ConverterFunctor<QJSValue, QList<QVariant>, QList<QVariant> ( *)(QJSValue const&)>::convert                                    qmetatype.h               398  0x7ffff721b162 
                8  QMetaType::convert                                                                                                                        qmetatype.cpp             739  0x7ffff6a0b36d 
                9  (anonymous namespace)::convert                                                                                                            qvariant.cpp              393  0x7ffff6a3ada1 
                10 QtPrivate::QVariantValueHelper<QList<QVariant>>::metaType                                                                                 qvariant.h                725  0x55555555a42e 
                11 QtPrivate::MetaTypeInvoker<QtPrivate::QVariantValueHelper<QList<QVariant>>, QVariant const&, QList<QVariant>>::invoke                     qvariant.h                115  0x5555555594c7 
                12 QtPrivate::QVariantValueHelperInterface<QList<QVariant>>::invoke                                                                          qvariant.h                793  0x5555555589f0 
                13 qvariant_cast<QList<QVariant>>                                                                                                            qvariant.h                860  0x55555555a536 
                14 QVariant::value<QList<QVariant>>                                                                                                          qvariant.h                362  0x555555559576 
                15 Contractor::executeTask                                                                                                                   Contractor.cpp            44   0x555555557a9a 
                16 QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<ContractorTask *>, void, void (Contractor:: *)(ContractorTask *)>::call qobjectdefs_impl.h        152  0x55555555e49b 
                17 QtPrivate::FunctionPointer<void (Contractor:: *)(ContractorTask *)>::call<QtPrivate::List<ContractorTask *>, void>                        qobjectdefs_impl.h        185  0x55555555e179 
                18 QtPrivate::QSlotObject<void (Contractor:: *)(ContractorTask *), QtPrivate::List<ContractorTask *>, void>::impl                            qobjectdefs_impl.h        414  0x55555555de01 
                19 QObject::event                                                                                                                            qobject.cpp               1249 0x7ffff6a21581 
                20 QCoreApplication::notifyInternal2                                                                                                         qcoreapplication.cpp      1061 0x7ffff69f4c18 
                21 QCoreApplication::sendEvent                                                                                                               qcoreapplication.cpp      1451 0x7ffff69f4dce 
                22 QCoreApplicationPrivate::sendPostedEvents                                                                                                 qcoreapplication.cpp      1800 0x7ffff69f7647 
                23 QCoreApplication::sendPostedEvents                                                                                                        qcoreapplication.cpp      1654 0x7ffff69f7b28 
                24 postEventSourceDispatch                                                                                                                   qeventdispatcher_glib.cpp 276  0x7ffff6a4c793 
                25 g_main_context_dispatch                                                                                                                                                  0x7ffff24dc417 
                26 ??                                                                                                                                                                       0x7ffff24dc650 
                27 g_main_context_iteration                                                                                                                                                 0x7ffff24dc6dc 
                28 QEventDispatcherGlib::processEvents                                                                                                       qeventdispatcher_glib.cpp 422  0x7ffff6a4bdcf 
                29 QEventLoop::exec                                                                                                                          qeventloop.cpp            225  0x7ffff69f357a 
                30 QThread::exec                                                                                                                             qthread.cpp               531  0x7ffff682b7dc 
                31 QThreadPrivate::start                                                                                                                     qthread_unix.cpp          361  0x7ffff682cd13 
                32 start_thread                                                                                                                              pthread_create.c          463  0x7ffff5bdd6db 
                33 clone                                                                                                                                     clone.S                   95   0x7ffff5f1688f                                            
                
                --> 5 <--
                
                1   QV4::Object::ownPropertyKeys                                                                                                              qv4object_p.h         367  0x7ffff713cbdd 
                2   QV4::ObjectIterator::ObjectIterator                                                                                                       qv4objectiterator_p.h 80   0x7ffff713cbdd 
                3   objectToVariant                                                                                                                           qv4engine.cpp         1397 0x7ffff713cbdd 
                4   toVariant                                                                                                                                 qv4engine.cpp         1359 0x7ffff713d949 
                5   QV4::ExecutionEngine::toVariant                                                                                                           qv4engine.cpp         1252 0x7ffff713dc10 
                6   QJSValue::toVariant                                                                                                                       qjsvalue.cpp          714  0x7ffff70521e4 
                7   convertJSValueToVariantType<QList<QVariant>>                                                                                              qv8engine.cpp         100  0x7ffff721b4c1 
                8   QtPrivate::ConverterFunctor<QJSValue, QList<QVariant>, QList<QVariant> ( *)(QJSValue const&)>::convert                                    qmetatype.h           398  0x7ffff721b162 
                9   QMetaType::convert                                                                                                                        qmetatype.cpp         739  0x7ffff6a0b36d 
                10  (anonymous namespace)::convert                                                                                                            qvariant.cpp          393  0x7ffff6a3ada1 
                11  QtPrivate::QVariantValueHelper<QList<QVariant>>::metaType                                                                                 qvariant.h            725  0x55555555a42e 
                12  QtPrivate::MetaTypeInvoker<QtPrivate::QVariantValueHelper<QList<QVariant>>, QVariant const&, QList<QVariant>>::invoke                     qvariant.h            115  0x5555555594c7 
                13  QtPrivate::QVariantValueHelperInterface<QList<QVariant>>::invoke                                                                          qvariant.h            793  0x5555555589f0 
                14  qvariant_cast<QList<QVariant>>                                                                                                            qvariant.h            860  0x55555555a536 
                15  QVariant::value<QList<QVariant>>                                                                                                          qvariant.h            362  0x555555559576 
                16  Contractor::executeTask                                                                                                                   Contractor.cpp        44   0x555555557a9a 
                17  QtPrivate::FunctorCall<QtPrivate::IndexesList<0>, QtPrivate::List<ContractorTask *>, void, void (Contractor:: *)(ContractorTask *)>::call qobjectdefs_impl.h    152  0x55555555e49b 
                18  QtPrivate::FunctionPointer<void (Contractor:: *)(ContractorTask *)>::call<QtPrivate::List<ContractorTask *>, void>                        qobjectdefs_impl.h    185  0x55555555e179 
                19  QtPrivate::QSlotObject<void (Contractor:: *)(ContractorTask *), QtPrivate::List<ContractorTask *>, void>::impl                            qobjectdefs_impl.h    414  0x55555555de01 
                20  QObject::event                                                                                                                            qobject.cpp           1249 0x7ffff6a21581 
                ... <More>                                                                                                                                                                              
                
                --> 6 <--
                
                1   QV4::Heap::String::append                  qv4string.cpp         235  0x7ffff714dcdc 
                2   QV4::Heap::String::simplifyString          qv4string.cpp         184  0x7ffff714de22 
                3   QV4::Heap::StringOrSymbol::createHashValue qv4string.cpp         245  0x7ffff714e185 
                4   QV4::Heap::StringOrSymbol::hashValue       qv4string_p.h         97   0x7ffff70ceb35 
                5   QV4::Heap::String::isEqualTo               qv4string_p.h         128  0x7ffff70ceb35 
                6   QV4::String::equals                        qv4string_p.h         203  0x7ffff70cb3db 
                7   QV4::QObjectWrapper::getQmlProperty        qv4qobjectwrapper.cpp 283  0x7ffff70cb3db 
                8   QV4::QObjectWrapper::getQmlProperty        qv4qobjectwrapper.cpp 414  0x7ffff70cbc4e 
                9   QV4::QQmlContextWrapper::virtualGet        qv4qmlcontext.cpp     246  0x7ffff70a6c66 
                10  QV4::Object::get                           qv4object_p.h         314  0x7ffff7055b65 
                11  QV4::ExecutionContext::getProperty         qv4context.cpp        360  0x7ffff7055b65 
                12  QV4::Runtime::method_loadName              qv4runtime.cpp        985  0x7ffff7143df0 
                13  QV4::Moth::VME::interpret                  qv4vme_moth.cpp       548  0x7ffff70e413e 
                14  QV4::Moth::VME::exec                       qv4vme_moth.cpp       441  0x7ffff70e7cc4 
                15  QV4::ArrowFunction::virtualCall            qv4functionobject.cpp 513  0x7ffff7080720 
                16  QV4::FunctionObject::call                  qv4functionobject_p.h 202  0x7ffff71474a3 
                17  QV4::Runtime::method_callName              qv4runtime.cpp        1346 0x7ffff71474a3 
                18  QV4::Moth::VME::interpret                  qv4vme_moth.cpp       745  0x7ffff70e3e37 
                19  QV4::Moth::VME::exec                       qv4vme_moth.cpp       441  0x7ffff70e7cc4 
                20  QV4::Function::call                        qv4function.cpp       68   0x7ffff707fade 
                ... <More>                                                                               
                
                
                K Offline
                K Offline
                kshegunov
                Moderators
                wrote on 21 May 2019, 19:13 last edited by
                #6

                @Matthew11 said in Passing custom type pointers between threads via signals and slots cause app to crash:

                So, If I understand it correctly, it gives me insights where and when another thread is working on resources from another thread?

                Indeed.

                So it happens when Contractor is working on _task in Contractor::executeTask(ContractorTask*) which is "normal" in this case. And these places should be protected. Am I right, that's the hint?

                Yes, although I'm not quite convinced you're going to manage that really gracefully. Why isn't the task something which belongs to a specific thread (i.e. moved to and operated on) by a single thread?

                Returning to stack traces, I generated them for the same code included before. App crashes seem to be connected with QV4Object. 3'rd and 6'th seem to be more common.

                Look down. These come from QML, there're calls into your objects that originate from different threads. I imagine that's because the Task has no notion of ownership. I'm not much into QML but it seems you get your code called from different threads, which is a bad idea.

                Is the table content enough or will it be better with screenshots?

                It's fine.

                Read and abide by the Qt Code of Conduct

                M 1 Reply Last reply 22 May 2019, 08:00
                3
                • K kshegunov
                  21 May 2019, 19:13

                  @Matthew11 said in Passing custom type pointers between threads via signals and slots cause app to crash:

                  So, If I understand it correctly, it gives me insights where and when another thread is working on resources from another thread?

                  Indeed.

                  So it happens when Contractor is working on _task in Contractor::executeTask(ContractorTask*) which is "normal" in this case. And these places should be protected. Am I right, that's the hint?

                  Yes, although I'm not quite convinced you're going to manage that really gracefully. Why isn't the task something which belongs to a specific thread (i.e. moved to and operated on) by a single thread?

                  Returning to stack traces, I generated them for the same code included before. App crashes seem to be connected with QV4Object. 3'rd and 6'th seem to be more common.

                  Look down. These come from QML, there're calls into your objects that originate from different threads. I imagine that's because the Task has no notion of ownership. I'm not much into QML but it seems you get your code called from different threads, which is a bad idea.

                  Is the table content enough or will it be better with screenshots?

                  It's fine.

                  M Offline
                  M Offline
                  Matthew11
                  wrote on 22 May 2019, 08:00 last edited by
                  #7

                  @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

                  Yes, although I'm not quite convinced you're going to manage that really gracefully.

                  This is why when I adopted mutexes in Contractor::executeTask(ContractorTask*) or inside ContractorTask it's still crashing? Or maybe it wasn't done well by me?

                  @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

                  Why isn't the task something which belongs to a specific thread (i.e. moved to and operated on) by a single thread?

                  So, when ContractorTask is shared (and called from different threads), it dramatically cut down the number of connections via threads and QML but also makes it vulnerable. And by using QVariant I can put there various data types from standard types to custom types, which I need in order to present user or send user input to the worker (and then further) which also cut down the number of connect's. And yeah, (correct me if I am wrong) I can do this with countable numbers of signals/slots passing different parameters with QueuedConnection and passing the data by value which is a (AFAIK) safe solution. But firstly I would like to give a try with using the sharaed resource and make it safe.

                  J 1 Reply Last reply 22 May 2019, 08:14
                  0
                  • M Matthew11
                    22 May 2019, 08:00

                    @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

                    Yes, although I'm not quite convinced you're going to manage that really gracefully.

                    This is why when I adopted mutexes in Contractor::executeTask(ContractorTask*) or inside ContractorTask it's still crashing? Or maybe it wasn't done well by me?

                    @kshegunov said in Passing custom type pointers between threads via signals and slots cause app to crash:

                    Why isn't the task something which belongs to a specific thread (i.e. moved to and operated on) by a single thread?

                    So, when ContractorTask is shared (and called from different threads), it dramatically cut down the number of connections via threads and QML but also makes it vulnerable. And by using QVariant I can put there various data types from standard types to custom types, which I need in order to present user or send user input to the worker (and then further) which also cut down the number of connect's. And yeah, (correct me if I am wrong) I can do this with countable numbers of signals/slots passing different parameters with QueuedConnection and passing the data by value which is a (AFAIK) safe solution. But firstly I would like to give a try with using the sharaed resource and make it safe.

                    J Offline
                    J Offline
                    J.Hilk
                    Moderators
                    wrote on 22 May 2019, 08:14 last edited by
                    #8

                    @Matthew11
                    are you by any chance exposing those thread-shared custom types directly to qml?

                    If yes, then that is a bad idea and my very well be the reason for your issues.


                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    M 1 Reply Last reply 22 May 2019, 08:39
                    3
                    • J J.Hilk
                      22 May 2019, 08:14

                      @Matthew11
                      are you by any chance exposing those thread-shared custom types directly to qml?

                      If yes, then that is a bad idea and my very well be the reason for your issues.

                      M Offline
                      M Offline
                      Matthew11
                      wrote on 22 May 2019, 08:39 last edited by Matthew11
                      #9

                      @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                      @Matthew11 are you by any chance exposing those thread-shared custom types directly to qml?

                      If yes, then that is a bad idea and my very well be the reason for your issues.

                      Unfortunately yes, and it actually happening:

                      // main.cpp:
                      engine.rootContext()->setContextProperty("Task", &Task);
                      

                      And in QML I am working directly on that shared resources:

                      // main.qml:
                      Task.setTaskID(_taskId)
                      Task.setContractorID(
                      TaskController.startTask(Task)
                      

                      OK, that's the good clue. Could you tell more why is that? Is it connected with JS / qml engine stuff?

                      J 1 Reply Last reply 22 May 2019, 08:52
                      0
                      • M Matthew11
                        22 May 2019, 08:39

                        @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                        @Matthew11 are you by any chance exposing those thread-shared custom types directly to qml?

                        If yes, then that is a bad idea and my very well be the reason for your issues.

                        Unfortunately yes, and it actually happening:

                        // main.cpp:
                        engine.rootContext()->setContextProperty("Task", &Task);
                        

                        And in QML I am working directly on that shared resources:

                        // main.qml:
                        Task.setTaskID(_taskId)
                        Task.setContractorID(
                        TaskController.startTask(Task)
                        

                        OK, that's the good clue. Could you tell more why is that? Is it connected with JS / qml engine stuff?

                        J Offline
                        J Offline
                        J.Hilk
                        Moderators
                        wrote on 22 May 2019, 08:52 last edited by
                        #10

                        @Matthew11
                        you should probably wrap that in manager class instead.

                        Could you tell more why is that? Is it connected with JS / qml engine stuff

                        most likely. I don't know enough about the inner workings to give you a definite answer. I can only tell you that I always ran into trouble when I tried to access/manipulate c++ threaded stuff (directly)via QML.

                        Since than I always have a manger object that forwards stuff via signals or from its own memory when exposed directly.


                        Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                        Q: What's that?
                        A: It's blue light.
                        Q: What does it do?
                        A: It turns blue.

                        M 1 Reply Last reply 22 May 2019, 09:07
                        1
                        • J J.Hilk
                          22 May 2019, 08:52

                          @Matthew11
                          you should probably wrap that in manager class instead.

                          Could you tell more why is that? Is it connected with JS / qml engine stuff

                          most likely. I don't know enough about the inner workings to give you a definite answer. I can only tell you that I always ran into trouble when I tried to access/manipulate c++ threaded stuff (directly)via QML.

                          Since than I always have a manger object that forwards stuff via signals or from its own memory when exposed directly.

                          M Offline
                          M Offline
                          Matthew11
                          wrote on 22 May 2019, 09:07 last edited by Matthew11
                          #11

                          @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                          you should probably wrap that in manager class instead.
                          Since than I always have a manger object that forwards stuff via signals or from its own memory when exposed directly.

                          I was going to do it like this.

                          Let's clarify some aspects of your approach.

                          1. Manager <-> Threads :
                          • communicate via signal/slots with QueuedConnection
                          • synchronization/locking on the shared resource

                          @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                          manger object that forwards stuff via signals or from its own memory when exposed directly.

                          1. Manager <-> QML
                          • signals and slots
                          • or directly from manager's memory

                          Have I figured it out properly?

                          J 1 Reply Last reply 23 May 2019, 05:17
                          0
                          • M Matthew11
                            22 May 2019, 09:07

                            @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                            you should probably wrap that in manager class instead.
                            Since than I always have a manger object that forwards stuff via signals or from its own memory when exposed directly.

                            I was going to do it like this.

                            Let's clarify some aspects of your approach.

                            1. Manager <-> Threads :
                            • communicate via signal/slots with QueuedConnection
                            • synchronization/locking on the shared resource

                            @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                            manger object that forwards stuff via signals or from its own memory when exposed directly.

                            1. Manager <-> QML
                            • signals and slots
                            • or directly from manager's memory

                            Have I figured it out properly?

                            J Offline
                            J Offline
                            J.Hilk
                            Moderators
                            wrote on 23 May 2019, 05:17 last edited by
                            #12

                            @Matthew11
                            jep, pretty much.
                            That at least is how I (would)do it.


                            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                            Q: What's that?
                            A: It's blue light.
                            Q: What does it do?
                            A: It turns blue.

                            1 Reply Last reply
                            2
                            • M Offline
                              M Offline
                              Matthew11
                              wrote on 25 May 2019, 20:02 last edited by Matthew11
                              #13

                              OK as @J.Hilk said:

                              @J.Hilk said in Passing custom type pointers between threads via signals and slots cause app to crash:

                              are you by any chance exposing those thread-shared custom types directly to qml?

                              And:

                              @J.Hilk said in Passing custom type pointers between QML and threads via signals and slots cause app to crash:

                              I can only tell you that I always ran into trouble when I tried to access/manipulate c++ threaded stuff (directly)via QML.

                              Indeed that was causing the crashes. The solution is to create a copy of the resource that is sent from QML and then send a copy of that resource to thread.

                              As @J.Hilk suggested Manager object should do the job which is:

                              @Matthew11 said in [Passing custom type pointers between QML and threads via signals and slots cause app to crash

                              1. Manager <-> Threads :
                              • communicate via signal/slots with QueuedConnection
                              • synchronization/locking on the shared resource
                              1. Manager <-> QML
                              • signals and slots
                              • or directly from the manager's memory

                              Below you can find my working example. This is very similar to the code which I provided in the first post. You send a dispatch from QML to specific Contractor, Contractor then is doing his job and return the result back to QML (sends task with input data scenario). Or you send a dispatch to Contractor to retrieve some data (send task with no input data scenario). ContractorTask is no longer exposed to QML. But pointers are no longer send however it is possible in the C++ domain (across main (Manager) and workers threads with proper locking/synchronization).

                              If you want to feel how it is when app is crashing uncomment the line _taskCopy.setData(_data); from pushTaskToContractor() in Controller.h which disabling the step of making the copy of the resource.

                              Thank you all for your help in solving the problem!

                              Code:

                              //.pro
                              
                              QT += quick
                              CONFIG += c++11
                              
                              SOURCES += \
                                      Contractor.cpp \
                                      main.cpp
                              
                              RESOURCES += qml.qrc
                              
                              HEADERS += \
                                  Contractor.h \
                                  ContractorTask.h \
                                  Controller.h
                              
                              // Contractor.h
                              
                              #ifndef CONTRACTOR_H
                              #define CONTRACTOR_H
                              
                              #include <QObject>
                              
                              #include <ContractorTask.h>
                              
                              class Contractor : public QObject
                              {
                                  Q_OBJECT
                              
                              public:
                                  Contractor(int _ID, QObject* parent = nullptr);
                              
                                  int getID() { return ID; }
                              
                              public slots:
                                  void executeTask(ContractorTask _task);
                              
                              signals:
                                  void finished();
                                  void taskStarted(ContractorTask _task);
                                  void taskFinished(ContractorTask _task);
                              
                              private:
                                  int ID;
                              };
                              
                              #endif // CONTRACTOR_H
                              
                              // Contractor.cpp
                              
                              #include "Contractor.h"
                              
                              #include <QDebug>
                              #include <QThread>
                              
                              Contractor::Contractor(int _ID, QObject *parent) :
                                  QObject(parent),
                                  ID(_ID)
                              {}
                              
                              void Contractor::executeTask(ContractorTask _task)
                              {
                                  emit(taskStarted(_task));
                              
                                  if(getID() != _task.getConctractorID())
                                  {
                                      qDebug() << "Not mine ID, discarding";
                                      return;
                                  }
                              
                                  QVariant localData = _task.getData();
                              
                                  switch(_task.getTaskID())
                                  {
                                  case 0: // PASS TASK TO C++ TO RETRIEVE DATA
                                  {
                                      QList<QVariant> _params;
                                      _params.append(12.5F);
                                      _params.append(14.36F);
                              
                                      QVariant _data = _params;
                              
                                      _task.setData(_data);
                              
                                      qDebug() << "PASS TASK TO C++ TO RETRIEVE DATA";
                                  }
                                      break;
                                  case 1: // PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML
                                  {
                                      QList<QVariant> _params;
                                      _params = localData.value<QList<QVariant>>();
                              
                                      QList<float> _floats;
                                      int counter = 0;
                                      for(auto item : _params)
                                      {
                                          _floats << item.toFloat();
                                          qDebug() << "Getting data in C++ from QML (QList<float>): item =" << counter++ << "value =" << item;
                                      }
                              
                                      qDebug() << "PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML";
                                  }
                                      break;
                                  default:
                                  {
                                      qDebug() << "Oh... I don't have these one :(";
                                  }
                                  }
                              
                                  emit(taskFinished(_task));
                              }
                              
                              // ContractorTask.h
                              
                              #ifndef CONTRACTORTASK_H
                              #define CONTRACTORTASK_H
                              
                              #include <QVariant>
                              
                              class ContractorTask
                              {
                              public:
                                  ContractorTask() :
                                      taskID(-1),
                                      contractorID(-1),
                                      data("")
                                  {}
                              
                                  int getTaskID() { return taskID; }
                              
                                  void setTaskID(int _ID) {taskID = _ID; }
                              
                                  int getConctractorID() { return contractorID; }
                              
                                  void setContractorID(int _ID) { contractorID = _ID; }
                              
                                  QVariant getData() { return data; }
                              
                                  void setData(QVariant _data) { data = _data; }
                              
                              private:
                                  int taskID;
                                  int contractorID;
                                  QVariant data;
                              };
                              
                              Q_DECLARE_METATYPE(ContractorTask)
                              
                              #endif // CONTRACTORTASK_H
                              
                              
                              // Controller.h
                              
                              #ifndef CONTROLLER
                              #define CONTROLLER
                              
                              #include <QObject>
                              #include <QThread>
                              #include <QDebug>
                              
                              #include <Contractor.h>
                              #include <ContractorTask.h>
                              
                              class Controller : public QObject
                              {
                                  Q_OBJECT
                                  QThread workerThread;
                              public:
                                  Controller()
                                  {
                                      Contractor *worker = new Contractor(0);
                                      worker->moveToThread(&workerThread);
                              
                                      connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
                              
                                      connect(this, &Controller::startTask, worker, &Contractor::executeTask);
                                      connect(worker, &Contractor::taskStarted, this, &Controller::contractorStartedTask);
                                      connect(worker, &Contractor::taskFinished, this, &Controller::contractorFinishedTask);
                                      workerThread.start();
                                  }
                              
                                  ~Controller()
                                  {
                                      workerThread.quit();
                                      workerThread.wait();
                                  }
                              
                              signals:
                                  void startTask(ContractorTask);
                                  void taskStarted(int id, int contractor, QVariant data);
                                  void taskEnded(int id, int contractor, QVariant data);
                              
                              public slots:
                                  void pushTaskToContractor(int _id, int _contractor, QVariant _data)
                                  {
                                      // QVariant depends to QML, so make COPY of QVariant CONTENT, before passing it to thread:
                                      QList<QVariant> _params;
                                      _params = _data.value<QList<QVariant>>();
                                      QVariant _dataToSend = _params;
                              
                                      ContractorTask _taskCopy;
                                      _taskCopy.setTaskID(_id);
                                      _taskCopy.setContractorID(_contractor);
                                      _taskCopy.setData(_dataToSend);                 // Sending local data copy is OK
                              
                              //        _taskCopy.setData(_data);                     // Sending _data (has source in QML) = PROGRAM CRASH!!!
                              
                                      emit(startTask(_taskCopy));
                                  }
                              
                                  void contractorFinishedTask(ContractorTask _task)
                                  {
                                      // Passing COPY of ContractorTask to QML:
                                      emit(taskEnded(_task.getTaskID(), _task.getConctractorID(), _task.getData()));
                                  }
                              
                                  void contractorStartedTask(ContractorTask _task)
                                  {
                                      // Passing COPY of ContractorTask to QML:
                                      emit(taskStarted(_task.getTaskID(), _task.getConctractorID(), _task.getData()));
                                  }
                              };
                              
                              #endif // CONTROLLER
                              
                              // main.cpp
                              
                              #include <QGuiApplication>
                              #include <QQmlApplicationEngine>
                              #include <Controller.h>
                              #include <QQmlContext>
                              
                              int main(int argc, char *argv[])
                              {
                                  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
                              
                                  QGuiApplication app(argc, argv);
                              
                                  Controller TaskController;
                                  qRegisterMetaType<ContractorTask>();
                              
                                  QQmlApplicationEngine engine;
                                  engine.rootContext()->setContextProperty("TaskController", &TaskController);
                              
                                  const QUrl url(QStringLiteral("qrc:/main.qml"));
                                  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                                                   &app, [url](QObject *obj, const QUrl &objUrl) {
                                      if (!obj && url == objUrl)
                                          QCoreApplication::exit(-1);
                                  }, Qt::QueuedConnection);
                                  engine.load(url);
                              
                              
                                  // Get item from QML, and connect it's signal (startTaskFromQML) to Controller
                                  QObject *item = engine.rootObjects().first();
                                  QObject::connect(item, SIGNAL(startTaskFromQML(int, int, QVariant)),
                                                   &TaskController, SLOT(pushTaskToContractor(int, int, QVariant)));
                              
                              
                                  return app.exec();
                              }
                              
                              // main.qml
                              
                              import QtQuick 2.12
                              import QtQuick.Controls 2.5
                              
                              ApplicationWindow {
                                  id: root
                                  visible: true
                                  width: 640
                                  height: 480
                                  title: qsTr("Test")
                              
                                  signal startTaskFromQML(int id, int contractor, variant data)
                                  property variant _data: 0
                              
                                  Connections {
                                      target: TaskController
                              
                                      onTaskEnded: console.log("Contractor with ID =", contractor, "finished task with ID = ", id, "and returned result:", data);
                              
                                      onTaskStarted: console.log("Contractor with ID =", contractor, "started task with ID = ", id);
                                  }
                              
                                  Column {
                                      id: column
                                      anchors.horizontalCenter: parent.horizontalCenter
                                      anchors.verticalCenter: parent.verticalCenter
                                      Button {
                                          id: passAndGet
                                          text: qsTr("PASS TASK WITH DATA TO C++ AND GET THE SAME DATA BACK IN QML")
                                          anchors.horizontalCenter: parent.horizontalCenter
                              
                                          onClicked: {
                                              _data= [1.2, 3.4, 5.6, 7.8]
                              
                                              for(var i = 0; i < 50; i++)
                                              {
                                                  root.startTaskFromQML(1, 0, _data)
                                              }
                                          }
                                      }
                              
                                      Button {
                                          id: getData
                                          text: qsTr("PASS TASK TO C++ TO RETRIEVE DATA")
                                          anchors.horizontalCenter: parent.horizontalCenter
                              
                                          onClicked: {
                                              _data = 0
                                              root.startTaskFromQML(0, 0, _data)
                                          }
                                      }
                                  }
                              }
                              
                              // qtquickcontrols2.conf
                              
                              [Controls]
                              Style=Material
                              
                              // qml.qrc
                              
                              <RCC>
                                  <qresource prefix="/">
                                      <file>main.qml</file>
                                      <file>qtquickcontrols2.conf</file>
                                  </qresource>
                              </RCC>
                              
                              1 Reply Last reply
                              2

                              10/13

                              22 May 2019, 08:52

                              • Login

                              • Login or register to search.
                              10 out of 13
                              • First post
                                10/13
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved