我正在尝试分析在访问由发送方线程创建并由接收方线程访问的堆分配对象时似乎发生的段错误。

这是代码的简短版本:

#include <QCoreApplication>
#include <QDebug>
#include <QThread>
#include <QTimer>

class Data
{
public:
    Data(int data1) : m_data1(data1) {}
    int data1() {
        return m_data1;
    }
private:
    int m_data1;
};

class Sender : public QObject
{
    Q_OBJECT

public:
    Sender(int timeout) : m_timeout(timeout) {}

public slots:
    void startSendingDatas() {
        QTimer::singleShot(m_timeout, [this]() {
            emit datas(new Data(3));
        });
    }

signals:
    void datas(Data *data);

private:
    int m_timeout;
};

class Receiver : public QObject
{
    Q_OBJECT

public slots:
    void onDatas(Data *data) {
        qDebug() << "data1 = " << data->data1();
        delete data; // is it always safe ?
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Sender sender(5000);
    Receiver receiver;

    QObject::connect(&sender, SIGNAL(datas(Data*)),
                     &receiver, SLOT(onDatas(Data*)));

    QThread worker;
    worker.start();

    sender.moveToThread(&worker);

    // now we call it asynchronously
    QMetaObject::invokeMethod(&sender, "startSendingDatas");

    return a.exec();
}

#include "main.moc"
Data不继承自QObject,因此在这里deleteLater不是一个选项,但这样做真的安全吗?

谢谢。

最佳答案

是的,这样做是“安全的”,如果您可以保证在访问指针时指针仍然有效。

在这个简单的例子中,情况似乎如此。我在您的代码中看到了一个潜在的问题,可能是您随机崩溃的原因:

事件驱动的对象只能在单个线程中使用。具体地说,这适用于计时器机制和网络模块。例如,您不能启动计时器或在不是对象线程的线程中连接套接字。

https://doc.qt.io/qt-5/threads-qobject.html段落对象重入。

这就是您正在执行的操作:在主线程上创建sender对象,然后在该线程上启动计时器,然后将其移至工作线程。

我不确定100%的另一件事:您在将对象移至另一个线程之前执行连接。默认情况下,如果不对连接进行任何说明,则当两个对象在同一线程上时,它是直接连接,而当对象在不同线程上时,显然是排队的连接。我不知道将对象移动时Qt可以扩展到哪种扩展类型,但是我宁愿先移动对象然后将其连接。

关于c++ - 在不同线程的插槽内删除分配给堆的对象是否安全?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61486462/

10-11 03:33
查看更多