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

C++ 为什么QTimer::singleShot在时间1而不是0阻止我的主线程,c++,macos,qt,signals-slots,qtimer,C++,Macos,Qt,Signals Slots,Qtimer,我一直在调试一些代码,这些代码似乎在GUI不可见时锁定了主线程。我已经将它剥离到下面的代码片段中,并且我已经发现在我的QTimer::singleShot实现中存在一个问题 为了复制这个问题,我将计时器设置为1(毫秒),启动应用程序循环并将应用程序窗口发送到后台。最终,应用程序将停止运行,直到UI进入前台 如果我将计时器设置为0,那么无论主应用程序窗口位于何处,它都会完美地运行,我已经将循环大小增加到400万,没有问题 我想我所坚持的是,两者之间的区别是什么 QTimer::singleShot

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

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

如果我将计时器设置为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;
};
class另一个对象:公共QObject
{
Q_对象
公众:
另一个对象();
无效过程();
信号:
无效完成();
};
名称空间用户界面{
类主窗口;
}
类主窗口:公共QMainWindow
{
Q_对象
公众:
显式主窗口(QWidget*parent=0);
~main窗口();
公众时段:
无效启动(bool);
专用插槽:
void emptyListOfAnotherObjects();
void delayEmptyOfAnotherObject();
私人:
QList m_其他对象的列表;
Ui::MainWindow*Ui;
};
==

AnotherObject::AnotherObject()
{
qDebug()开始,信号(点击(bool)),这个,插槽(开始(bool));
}
MainWindow::~MainWindow()
{
删除用户界面;
}
void主窗口::开始(bool)
{
对于(长i=0;i可能是该问题的原因

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

无论如何,可以从应用程序中禁用应用程序nap,如前所述

在使用Qt时,您需要使用.mm文件来解决此问题。

可能是导致此问题的原因

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

无论如何,可以从应用程序中禁用应用程序nap,如前所述


使用Qt时,您需要使用.mm文件来解决问题。

我尝试了您的代码,但无法重现您的问题。在0和1ms的时间内一切正常。您所说的“将应用程序发送到后台”是什么意思?我尝试了很多东西,但它似乎运行得很流畅。@aManFromOuterSpace-你在什么平台上测试它?如果你使用的是OS X,可能是因为一旦主窗口到达前台,我单击一个按钮开始循环,然后单击另一个打开的窗口,在我的例子中是QtCreator,然后将该应用程序带到前台,我的应用程序就会转到back.我也做了同样的事情。在Win10上,Qt 5.5.1,64位,它可以工作!作为,你可以通过检查活动监视器,启用“App Nap”列来测试这一点,以显示哪些进程处于这种状态。我尝试了你的代码,但我无法重现你的问题。一切都可以在0和1ms下正常工作。你说“将应用发送到后台”是什么意思?我尝试了很多东西,但它似乎运行得很流畅。@aManFromOuterSpace-你在什么平台上测试它?如果你使用的是OS X,可能是因为一旦主窗口到达前台,我单击一个按钮开始循环,然后单击另一个打开的窗口,在我的例子中是QtCreator,然后将该应用程序带到前台,我的应用程序就会转到ba我也做了同样的事情。在Win10上,Qt5.5.1,64位,它可以工作!作为,您可以通过检查活动监视器,启用“App Nap”列,以显示哪些进程处于这种状态来测试它。
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()));
}