Qt 5.12 время от времени SIGSEGV при вызове C ++ из Qml - PullRequest
0 голосов
/ 16 января 2019

Внутри моего приложения есть кнопка Qml с 2 состояниями (подключение / отключение). Вот соответствующий код:

        Button {
           id : connectDisconnectButton
           anchors.centerIn: parent
           property bool isConnected : false
           text : isConnected ? qsTr("Disconnect") : qsTr("Connect")
           antialiasing: true

           property var currentConnectionParams : ({})

           onClicked: {
              if ( isConnected ) {
                 proxy.disconnectFromEmulatorService();
              } else {
                 connectDisconnectButton.currentConnectionParams["port"] = serviceConnectionPort.getValue();
                 connectDisconnectButton.currentConnectionParams["ip_addr"] = String(serviceConnectionIpPart_0.getValue())
                       + String(".") + String(serviceConnectionIpPart_1.getValue())
                 + String(".") + String(serviceConnectionIpPart_2.getValue())
                 + String(".") + String(serviceConnectionIpPart_3.getValue());

                 proxy.connectToEmulatorService( connectDisconnectButton.currentConnectionParams );
              }

              isConnected = !isConnected;
           }
        }

Я вижу, что время от времени я получаю SIGSEGV при вызове метода connectToEmulatorService моего прокси-сервера C ++. Вот соответствующий код C ++:

Q_INVOKABLE void connectToEmulatorService( QVariant in )
{
   m_serviceConnectionParams = in;
   emit connectionInitiatedSignal();
   m_functorExecutor->executeFunctor( boost::bind(&EmulatorControlProxy::connectToEmulatorServiceImpl, this ) );
}

void connectToEmulatorServiceImpl()
{
   QMap<QString, QVariant> connectionParams_ = m_serviceConnectionParams.toMap();
   try {
      emit connectionOkSignal();
   }catch(...) {
      Error("connectToEmulatorServiceImpl failure : ip = %s, port = %s",
            connectionParams_["ip_addr"].toString().toStdString().c_str(),
            connectionParams_["port"].toString().toStdString().c_str() );
      emit connectionFailedSignal();
   }
}

Функция обратной трассировки GDB дает следующий вывод:

(gdb) backtrace
#0  0x00007ffff6e0777b in QV4::QObjectWrapper::virtualGet(QV4::Managed const*, QV4::PropertyKey, QV4::Value const*, bool*) ()
    at /home/developer/Qt5.12.0/5.12.0/gcc_64/lib/libQt5Qml.so.5
#1  0x00007ffff6e8802b in QV4::Runtime::method_loadProperty(QV4::ExecutionEngine*, QV4::Value const&, int) () at /home/developer/Qt5.12.0/5.12.0/gcc_64/lib/libQt5Qml.so.5
#2  0x00007fffe0003d9a in  ()
#3  0x0000000000000000 in  ()

В чем может быть причина этого? Как это побороть? Qt 5.12 Ubuntu 18.10 g ++ 7.3 7.3

PS. Проблема как-то связана с

QMap<QString, QVariant> connectionParams_ = m_serviceConnectionParams.toMap();

Кажется, что временная карта объектов QML удаляется до того, как поток functorExecutor попытается получить к ней доступ. Но почему это происходит, если я копирую входящий QVariant в переменную члена класса? В качестве обходного пути я объявил связку Q_PROPERTY для моего прокси-сервера для хранения там данных QML перед вызовом C ++. И это похоже на работу. Но я считаю, что где-то в Qt есть проблема. Любая помощь приветствуется.

1 Ответ

0 голосов
/ 22 января 2019

Вот официальный ответ от Qt-JIRA:

"Вы получаете доступ к своим m_connectionParams из двух разных потоков без блокировки. Основной поток записывает его в connectToEmulatorService (), а рабочий поток читает его вconnectToEmulatorServiceImpl (). Если основной поток пишет снова, когда рабочий поток только читает предыдущую итерацию, вы получаете сбой. Это наиболее очевидная проблема.

Однако, даже если вы заблокировали мьютекс для доступадля m_connectionParams, это все равно будет небезопасно. Вариант, который у вас есть, это внутренне QJSValue. Чтобы преобразовать это в карту, мы должны вызвать глубоко в движке JavaScript, создать области и взаимодействовать с кучей JavaScript.любой другой JavaScript выполняется одновременно в другом потоке, у вас проблемы.

Просто извлеките QVariantMap из основного потока и передайте его функтору в качестве параметра. "

Итак, иметь копию QVariant недостаточно ... этогде-то глубоко внутри источников Qt.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...