为什么QTimer::singleShot在时间1阻塞了我的主线程而不是0

Why does QTimer::singleShot block my main thread at time 1 but not 0

本文关键字:线程 我的 singleShot QTimer 时间 为什么      更新时间:2023-10-16

我一直在调试一些代码,当GUI不可见时,这些代码似乎锁定了主线程。我已经把它剥离到下面的代码片段中,并且我发现在我的QTimer::singleShot实现中存在一个问题。

为了复制这个问题,我将计时器设置为1(毫秒),启动应用程序循环,并将应用程序窗口发送到后台。最终,该应用程序将陷入停顿,直到用户界面进入前台。

如果我将计时器设置为0,那么无论主应用程序窗口位于何处,它都会完美运行,我已经将循环大小增加到400万,没有问题。

我想我一直在想,之间有什么区别

QTimer::singleShot(1, this, SLOT(emptyListOfAnotherObjects()));

QTimer::singleShot(0, this, SLOT(emptyListOfAnotherObjects()));

为什么一个会阻塞主线程而不是另一个?

值得注意的是,在不同的线程中运行这个循环,保持GUI独立,会导致相同的问题。

class AnotherObject : public QObject
{
    Q_OBJECT
public:
    AnotherObject();
    void process();
signals:
    void done();
};
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
    void start(bool);
private slots:
    void emptyListOfAnotherObjects();
    void delayEmptyOfAnotherObject();
private:
    QList<AnotherObject*> m_listOfAnotherObject;
    Ui::MainWindow *ui;
};

===

AnotherObject::AnotherObject()
{
    qDebug() << "CTOR AnotherObject" << this;
}
void AnotherObject::process()
{
    emit done();
    deleteLater();
}
//==
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->start, SIGNAL(clicked(bool)), this, SLOT(start(bool)));
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::start(bool)
{
    for(long i=0; i<40000; i++){
        m_listOfAnotherObject.append(new AnotherObject());
    }
    emptyListOfAnotherObjects();
}
void MainWindow::emptyListOfAnotherObjects()
{
    if(m_listOfAnotherObject.isEmpty()) {
        qDebug() << "List empty, done.";
        return;
    }
    AnotherObject* i = m_listOfAnotherObject.takeFirst();
    connect(i, SIGNAL(done()), this, SLOT(delayEmptyOfAnotherObject()));
    i->process();
    qDebug() << m_listOfAnotherObject.count();
}
void MainWindow::delayEmptyOfAnotherObject()
{
    QTimer::singleShot(1, this, SLOT(emptyListOfAnotherObjects()));
}

感谢

更新:

抱歉,我应该补充一下,这是OSX上的Qt 5.2。

App Nap可能是导致此问题的原因。

我怀疑使用invokeMethod会在线程的事件队列中放置一条消息,从而防止应用程序打盹。相反,使用QTimer会等待并检查超时,因此空的事件队列将允许它进入小睡状态。

无论如何,可以从您的应用程序中禁用应用程序小睡,如下所述。

在使用Qt时,您需要使用一个.mm文件来封装objective-c代码。