Nano Hash - криптовалюты, майнинг, программирование

Как остановить Qthread после вызова movetothread()?

Когда я повторно реализую QTcpserver::incomingConnection(), создается новый QThread и новый QTcpsocket. accept-fd передается в QTcpsocket. Однако предупреждение возникает, когда весь процесс неожиданно завершается: QThread: уничтожен, пока поток все еще выполняется, так как Qthread вызывает quit(), и два объекта будут удалены. Вот код ниже.

 void TcpServer::incomingConnection(qintptr handle)
{
    QThread* tcpThread = new QThread;
    TcpSocket* tcpSocket = new TcpSocket;

    tcpSocket->setSocketDescriptor(handle);
    tcpSocket->moveToThread(tcpThread);

    connect(tcpSocket,&TcpSocket::sigRecvFinish, [=](){
        tcpThread->quit();
        delete tcpSocket;
        delete tcpThread;
    });
    tcpThread->start();
}

Как я могу выйти из потока и правильно освободить ресурсы? Между тем, что вызывает эту проблему? Буду признателен, если вы поможете мне с этим вопросом.


Ответы:


1

Прежде всего, Qt имеет хороший асинхронный API, поэтому использование потоков (в этом контексте) полностью устарело и является пустой тратой ресурсов.

Используя лямбда в операторе подключения, вы потеряли функциональность переключения потоков, которая по умолчанию выполняется connect. В результате вы пытаетесь уничтожить объект потока из потока, которым этот объект управляет.

Обратите внимание, что последний аргумент QObject::connect: Qt::ConnectionType type = Qt::AutoConnection (соединения без лямбда). Когда используется лямбда, QObject::connect не имеет такого функциональность и код вызываются из потока, вызвавшего сигнал.

Отбрасывание лямбды гарантирует, что каждый вызов будет выполняться в правильном потоке.

void TcpServer::incomingConnection(qintptr handle)
{
    QThread* tcpThread = new QThread;
    TcpSocket* tcpSocket = new TcpSocket;

    tcpSocket->setSocketDescriptor(handle);
    tcpSocket->moveToThread(tcpThread);

    connect(tcpSocket, &TcpSocket::sigRecvFinish, tcpSocket, &QBject::delteLater);
    connect(tcpSocket, &TcpSocket::sigRecvFinish, tcpThread, &QThread::quit);
    connect( tcpThread, &QThread::finished, tcpThread, &QThread::deleteLater );

    tcpThread->start();
}

Технические подробности см.

Пространство имен Qt | Qt Core 5.15.3

Constant Value Description
Qt::AutoConnection 0 (Default) If the receiver lives in the thread that emits the signal, Qt::DirectConnection is used. Otherwise, Qt::QueuedConnection is used. The connection type is determined when the signal is emitted.
23.04.2021
  • Спасибо за ваш ответ, и код работает без предупреждений. Есть еще два вопроса. Во-первых, как я могу убедиться, что Qthread удален правильно и ресурсы освобождены? Кстати, почему «удалить» кажется странным? Каков правильный способ уничтожить объект в Qt-программировании? Рекомендуется ли использовать QObject::deleteLater, когда объект, предлагаемый Qt, необходимо удалить? 25.04.2021
  • deleteLater — это слот, поэтому его можно соединить с Qt::AutoConnection. Таким образом, не зависит от того, какой сигнал протектора испускается, удаление будет выполняться в потоке, к которому принадлежит объект. Это единственная причина использовать здесь deleteLater. Я думаю, вам следует более внимательно прочитать мой ответ и прочитать связанную документацию. 25.04.2021
  • спасибо! Вещи стали более ясными. 26.04.2021

  • 2

    Вам нужно заменить connect на следующий код:

    connect( tcpSocket, &TcpSocket::sigRecvFinish, tcpSocket, &QObject::deleteLater );
    connect( tcpSocket, &QObject::destroyed, tcpThread, &QThread::quit );
    connect( tcpThread, &QThread::finished, tcpThread, &QThread::deleteLater );
    
    23.04.2021
  • UP: исправить удаление самого tcpSocket 23.04.2021
  • это из оригинальной формы кода OP, да, это странно, но приемлемо. 23.04.2021
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..