为什么QTimer :: singleShot在时间1阻止我的主线程但不阻止0

时间:2016-04-04 11:52:31

标签: c++ macos qt signals-slots qtimer

我一直在调试一些代码,这些代码在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;
};

==

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。

1 个答案:

答案 0 :(得分:2)

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

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

无论如何,可以在应用程序中禁用app nap,如here所述。

当您使用Qt时,您需要将.mm文件用于encapsulate the objective-c code