头发继续乱 2024-07-26 08:54 采纳率: 47.4%
浏览 21
已结题

QThread: Destroyed while thread is still running,找不到是哪一个线程要被销毁

在checkConn的 m_loop.exec(); 等待时 发生,闪退 报错:QThread: Destroyed while thread is still running,但是这个cpp中两个线程从代码分析 都没有要删除销毁的趋势,外部是通过

EcmApiDataSender sender;
    if (!m_port.isEmpty())
    {
        sender.setPort(m_port);
    }
    QString uuid = sender.sendReq(callName, params);

调用

#include "EcmApiDataSender.h"
#include <nlohmann/json.hpp>

using std_json = nlohmann::json;

EcmApiDataSender::EcmApiDataSender()
{
    if (!m_socketThread)
    {
        m_socketThread = new QThread();
        m_socketThread->setObjectName("我是Sock线程");
        m_socketThread->start();
    }

    if (!m_invoker) {
        m_invoker = new EcmApiSocketInvoker();
        m_invoker->moveToThread(m_socketThread);
        connect(m_invoker, SIGNAL(sendFailed(qint64, const QString&)), this, SLOT(handleSendFailed(qint64, const QString&)), Qt::AutoConnection);

    }

    m_timer = new QTimer();
    m_timerThread = new QThread();
    m_timerThread->setObjectName("我是timer");
    connect(m_timerThread, &QThread::started, [&] {
        m_timer->start(m_socketTimeout);
    });
    connect(m_timerThread, &QThread::finished, m_timer , &QTimer::stop);
    connect(m_timerThread, &QThread::destroyed, m_timer, &QTimer::deleteLater);
}

EcmApiDataSender& EcmApiDataSender::getInstance()
{
    static EcmApiDataSender ins;
    return ins;
}

EcmApiDataSender::~EcmApiDataSender()
{
    LOG(INFO)<<"EcmApiDataSender析构函数start";
    disConn();
    if (m_timerThread)
    {
        m_timerThread->requestInterruption();
        m_timerThread->quit();
        QThread::msleep(100);
        m_timerThread->deleteLater();
    }
    if (m_socketThread) {
        m_socketThread->requestInterruption();
        m_socketThread->quit();
        QThread::msleep(100);
        m_socketThread->deleteLater();
    }
    LOG(INFO)<<"EcmApiDataSender析构函数";
}

void EcmApiDataSender::conn()
{
    if (!m_socket)
    {
        LOG(INFO)<<"new Conn";
        m_socket = new QWebSocket();
        m_socket->moveToThread(m_socketThread);
        connect(m_socketThread, &QThread::finished, m_socket, &QObject::deleteLater);
        connect(m_socketThread, &QThread::finished, this, &EcmApiDataSender::handle1);
        connect(this, SIGNAL(sendMessage(QWebSocket*, const QString&)), m_invoker, SLOT(sendMessage(QWebSocket*, const QString&)), Qt::AutoConnection);
        connect(this, SIGNAL(open(QWebSocket*, const QString&)), m_invoker, SLOT(open(QWebSocket*, const QString&)), Qt::AutoConnection);
        connect(this, SIGNAL(close(QWebSocket*)), m_invoker, SLOT(close(QWebSocket*)), Qt::AutoConnection);
        connect(m_socket, &QThread::destroyed, m_invoker, &EcmApiSocketInvoker::deleteLater,Qt::AutoConnection);
    }
    LOG(INFO) << "socket connect";
    QUrl local(m_url);
    connect(m_socket, SIGNAL(textMessageReceived(QString)), this, SLOT(handleMessageReceived(QString)), Qt::AutoConnection);
    connect(m_socket, SIGNAL(connected()), this, SLOT(handleConnected()), Qt::AutoConnection);
    connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(handleError(QAbstractSocket::SocketError)), Qt::AutoConnection);
    connect(m_timer, SIGNAL(timeout()), this, SLOT(handleTimeout()), Qt::AutoConnection);
    //connect(m_timerThread, &QThread::destroyed, this, &EcmApiDataSender::handle1,Qt::AutoConnection);
    connect(m_socketThread, &QThread::destroyed, this, &EcmApiDataSender::handle2,Qt::AutoConnection);
    connect(m_socket, &QThread::destroyed, this, &EcmApiDataSender::handle3,Qt::AutoConnection);
    m_connReport = false;
    m_timer->moveToThread(m_timerThread);
    m_timerThread->start();


    emit open(m_socket, m_url);
}

void EcmApiDataSender::disConn()
{
    LOG(INFO) << "socket disconnect";
    if (m_socket && m_socket->isValid())
    {
        emit close(m_socket);
    }
}

void EcmApiDataSender::checkConn()
{
    LOG(INFO) << "检测桥接服务连接状态";
    if (!m_socket || m_socket->state() != QAbstractSocket::ConnectedState)
    {
        LOG(INFO) << "检测到未连接,开始连接桥接服务";
        m_locker.lockForWrite();

        conn();

        m_loop.exec();
        m_locker.unlock();
        if (!m_connReport) {
            LOG(INFO) << "连接失败";
        }
    }
    LOG(INFO) << "连接正常";
}

QString EcmApiDataSender::getRetMsg(const QString& uuid)
{
    m_locker.lockForRead();
    QString retMsg = m_retMsg[uuid].toString();
    m_locker.unlock();
    return retMsg;
}

bool EcmApiDataSender::hasResult(const QString& uuid)
{
    m_locker.lockForRead();
    if (m_retMsg.contains(uuid))
    {
        m_locker.unlock();
        return true;
    }
    m_locker.unlock();
    return false;
}

QString EcmApiDataSender::sendReq(const QString& callName, const QString& params)
{
    cleanResult();
    checkConn();
    QString uuid = QUuid::createUuid().toString().remove("{").remove("}").remove("-");
    QJsonObject obj;
    obj["method"] = callName;
    obj["params"] = params;
    obj["guid"] = uuid;
    QJsonDocument doc;
    doc.setObject(obj);
    auto sendMsg = doc.toJson();
    LOG(INFO) << "sendmessage:" << sendMsg.toStdString();
    emit sendMessage(m_socket, sendMsg);
    return uuid;
}

void EcmApiDataSender::setUrl(const QString& url)
{
    m_url = url;
}

void EcmApiDataSender::setPort(const QString& port)
{
    m_url = m_defaultUrl.replace("<port>", port);
    m_port = port;
}

QString EcmApiDataSender::getPort()
{
    return m_port;
}

void EcmApiDataSender::setSocketTimeout(int timeout)
{
    m_socketTimeout = timeout;
}

void EcmApiDataSender::quitWait()
{
    if (m_loop.isRunning()) {
        m_loop.quit();
        m_timerThread->quit();
    }
}

void EcmApiDataSender::cleanResult()
{
    if (!m_retLifeTime.isEmpty()) {
        m_locker.lockForWrite();
        auto deadTime = QDateTime::currentDateTime().addSecs(-2);
        for (auto it = m_retLifeTime.begin(); it != m_retLifeTime.end(); ) {
            if (it.value() < deadTime)
            {
                m_retMsg.remove(it.key());
                m_retLifeTime.erase(++it);
                continue;
            }
            it++;
        }
        m_locker.unlock();
    }
    
}

void EcmApiDataSender::handleConnected()
{
    LOG(INFO) << "连接成功";
    m_connReport = true;
    quitWait();
}

void EcmApiDataSender::handleError(QAbstractSocket::SocketError err)
{
    QMetaEnum m = QMetaEnum::fromType<QAbstractSocket::SocketError>();
    LOG(INFO) << "连接错误:" << m.value(err);
    quitWait();
}

void EcmApiDataSender::handleTimeout()
{
    if (m_loop.isRunning()) {
        LOG(INFO) << "连接超时";
        quitWait();
    }
}
void EcmApiDataSender::handle1(){
    LOG(INFO)<<"我被销毁了";

}
void EcmApiDataSender::handle2(){
    LOG(INFO)<<"我被销毁了2";

}


void EcmApiDataSender::handle3(){
    LOG(INFO)<<"我被销毁了3";

}

void EcmApiDataSender::handleSendFailed(qint64 ret, const QString& msg)
{
    LOG(INFO) << "sendFailed retCode " << ret;
    LOG(INFO) << "接收发送错误返回消息:" << msg.toStdString();
    QJsonParseError err;
    QJsonDocument doc = QJsonDocument::fromJson(msg.toStdString().data(), &err);
    if (err.error != QJsonParseError::NoError)
    {
        LOG(INFO) << "报文转换失败,内容:" << msg.toStdString() << ",错误信息:" << err.errorString().toStdString();
        return;
    }
    auto obj = doc.object();
    auto guid = obj["guid"].toString();
    if (guid.isEmpty())
    {
        LOG(INFO) << "报文解析失败:guid为空";
        return;
    }
    m_locker.lockForWrite();
    m_retMsg[guid] = "影像api调用失败";
    m_retLifeTime[guid] = QDateTime::currentDateTime();

    m_locker.unlock();
    quitWait();
}

void EcmApiDataSender::handleMessageReceived(const QString& msg)
{
    if (msg.isEmpty())
    {
        LOG(INFO) << "检测到空消息";
        return;
    }
    LOG(INFO) << "接收返回消息:" << msg.toStdString();

    QJsonParseError err;
    QJsonDocument doc = QJsonDocument::fromJson(msg.toStdString().data(), &err);
    if (err.error != QJsonParseError::NoError)
    {
        LOG(INFO) << "报文转换失败,内容:" << msg.toStdString() << ",错误信息:" << err.errorString().toStdString();
        return;
    }
    auto obj = doc.object();
    auto guid = obj["guid"].toString();
    if (guid.isEmpty()) {
        LOG(INFO) << "报文解析失败:guid为空";
        return;
    }
    auto message = obj["message"].toString();
    m_locker.lockForWrite();
    m_retMsg[guid] = message;
    m_retLifeTime[guid] = QDateTime::currentDateTime();

    m_locker.unlock();
}


  • 写回答

4条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-07-26 09:06
    关注

    引自免费微信小程序:皆我百晓生

    你的问题似乎是在使用Qt框架中的线程管理时遇到了问题。你遇到了一个错误提示:“QThread: Destroyed while thread is still running”。这个错误通常意味着你在线程仍在运行时尝试删除或销毁了一个线程对象。这可能会导致程序崩溃或其他未定义的行为。

    从你提供的代码来看,有两个线程,一个是m_socketThread,另一个是m_timerThread。你的EcmApiDataSender类中有许多方法和对象涉及到这两个线程的生命周期管理。但在提供的代码中,并没有看到明显的线程销毁操作不当的问题。不过,为了解决这个问题,我建议你检查以下几点:

    1. 确保所有对线程的操作都在正确的时间进行。例如,在调用quit()wait()方法之前,确保线程已经完成了它的任务并退出了运行。这可以通过检查线程的isRunning()状态来实现。
    2. 确保你没有在销毁一个线程后再次使用它。从代码看,你的EcmApiDataSender析构函数中尝试删除这两个线程,但在其他地方可能还存在引用这些线程的地方。你需要确保在析构函数执行后,其他地方不再引用或操作这两个线程对象。特别是在析构函数和其他涉及线程操作的方法中,需要小心管理线程的生命周期。
    3. 检查是否有其他地方也在管理这两个线程的生命周期。例如,如果其他地方也调用了线程的deleteLater()方法,可能会导致冲突或意外的行为。

    另外,为了帮助你更好地理解问题,你可以尝试在代码中添加更多的日志输出,以追踪线程的生命周期和状态变化。这样可以帮助你找到问题的根源。

    如果你还有其他关于这个问题的疑问或需要进一步的帮助,请告诉我!

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 9月24日
  • 已采纳回答 9月16日
  • 创建了问题 7月26日

悬赏问题

  • ¥15 vue请求不到数据,返回状态200,数据为html
  • ¥15 访问url时不会自动调用其 Servlet的doGet()
  • ¥15 用白鹭引擎开发棋牌游戏的前端为什么这么难找
  • ¥15 MATLAB解决问题
  • ¥35 哪位专业人士知道这是什么原件吗?哪里可以买到?
  • ¥15 关于#c##的问题:treenode反序列化后获取不到上一节点和下一节点,Fullpath和Handle报错
  • ¥15 一部手机能否同时用不同的app进入不同的直播间?
  • ¥20 输入import torch显示Intel MKL FATAL ERROR,系统驱动1%,: Cannot load mkl_intel_thread.dll.
  • ¥15 点云密度大则包围盒小
  • ¥15 nginx使用nfs进行服务器的数据共享