2016-04-04 19 views
0

Ich habe einige Code debuggen, der den Haupt-Thread zu sperren scheint, wenn die GUI nicht sichtbar ist. Ich habe es direkt zurück zu dem folgenden Codeausschnitt entfernt und ich habe festgestellt, dass ein Problem um meine Implementierung von QTimer :: singleShot besteht.Warum blockiert QTimer :: singleShot meinen Haupt-Thread zur Zeit 1, aber nicht 0

Um das Problem zu replizieren, setze ich den Timer auf 1 (Millisekunde) starten Sie die Anwendung Schleife und senden Sie das App-Fenster an den Hintergrund. Schließlich wird die App zum Stillstand kommen, bis die Benutzeroberfläche in den Vordergrund gebracht wird.

Wenn ich den Timer auf 0 setze, dann läuft das einwandfrei, egal wo sich das Haupt-App-Fenster befindet, ich habe die Loop-Größe bis auf 4 Millionen ohne Problem erhöht.

ich denke, ich bin fest, was mit ist, was der Unterschied zwischen

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

und

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

Warum blockiere ich den Hauptfaden über den anderen?

Für das, was es wert ist, diese Schleife in einem anderen Thread auszuführen, führt das Beibehalten der GUI zu demselben Problem.

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())); 
} 

Dank

Update:

Es sollte hinzugefügt, dass dies Qt 5.2 auf OSX.

+0

Ich habe Ihren Code ausprobiert und kann Ihr Problem nicht reproduzieren. Alles funktioniert gut bei 0 und 1ms. Was meinst du mit "Senden der App an den Hintergrund"? Ich habe viele Sachen ausprobiert, aber es scheint flüssig zu laufen. – Paraboloid87

+3

@aManFromOuterSpace - Auf welcher Plattform testen Sie dies? Wenn Sie OS X verwenden, kann es aufgrund von [App Nickerchen] sein (https://developer.apple.com/library/mac/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/AppNap.html) – TheDarkKnight

+0

Sobald das Hauptfenster kommt Vordergrund Ich klicke auf eine Schaltfläche, um die Schleife zu starten, dann klicke auf ein anderes geöffnetes Fenster, QtCreator in meinem Fall, und bringe diese App in den Vordergrund und meine App geht nach hinten. – aManFromOuterSpace

Antwort

1

App Nap ist wahrscheinlich die Ursache für dieses Problem.

Ich vermute, dass die Verwendung von invokeMethod eine Nachricht in der Ereigniswarteschlange des Threads platziert, die verhindert, dass die App schlummert. Im Gegensatz dazu wartet die Verwendung von QTimer und überprüft das Zeitlimit, sodass eine leere Ereigniswarteschlange es ermöglicht, in den Ruhezustand einzutreten.

Jedenfalls ist es möglich, App-Nickerchen innerhalb Ihrer Anwendung zu deaktivieren, wie beschrieben here.

Da Sie Qt verwenden, sollten Sie eine .mm-Datei zu encapsulate the objective-c code verwenden.