2013-03-13 1 views
2

Plate-forme: Win7 x64, MinGW-rubenvb (4.7.2-x64), Qt 4.8Qt fin fraient fil par QConcurrent :: run

Dire que j'ai quelques tâches longues (lire le fichier de la population, écrire dans le fichier de la population, et exécuter la simulation) a donné naissance à l'aide QConcurrent :: run, comme suit:

void MainWindow::runLengthyJob() { 
    /* some setup */ 
    jobWatcher->setFuture(QConcurrent::run(theApp, &AppClass::lengthyJob)); 
    // lengthyJob - can be readPop(), writePop(), runSim() 
} 

Habituellement ces tâches prennent au moins 15 secondes pour terminer (pour la simulation, il faut plus d'heures). Pour éviter de s'écraser-fils ne sont pas encore finis, je réimplémenter MainWindow :: closeEvent comme suit:

void MainWindow::closeEvent(QCloseEvent *event) { 
    /* wait for any dangling thread */ 
    if (QThreadPool::globalInstance()->activeThreadCount()) 
     QThreadPool::globalInstance()->waitForDone(); 
    event->accept(); 
} // end: MainWindow::closeEvent 

Cela fonctionne bien, mais quand je clique sur le bouton « x » de MainWindow, il semble froid et montrant "Ne répond pas" (je suppose que le texte est donné par OS), même si elle a finalement mis fin à l'application.

Je souhaite quitter l'application dès que l'emplacement close() de MainWindow est déclenché. Alors, comment puis-je raccourcir le temps d'attente pour les threads pas encore finis? Ou comment puis-je informer l'utilisateur qu'un long travail est en cours (ce qui peut prendre des heures avant d'être complètement arrêté)? (J'ai essayé d'inclure QDialog/QMessageBox dans closeEvent mais les nouvellement créés widgets congèle aussi)

Note: Pour AppClass: lengthyJobs [readPop()/writePop()], ce sont des fonctions autonomes et je ne peux pas briser les bas à étapes plus petites. Pour AppClass :: runSim(), des étapes plus petites peuvent être possibles.

Répondre

0

Tout d'abord, le futur, retourné par QtConcurrent :: run ne supporte pas l'annulation. Donc vous ne pouvez pas l'annuler. Le mieux que vous puissiez faire est de placer un drapeau dans l'AppClass et de le vérifier dans vos longsJobs (comme vous l'avez dit dans le cas de runSim), puis d'attendre la fin. De toute façon, si vous voulez informer l'utilisateur de la tâche en cours d'exécution, vous pouvez faire ce qui suit: créer une sous-classe de QDialog, par exemple WaitDialog avec QTimer avec un certain temps, démarrer ce minuteur lors de la construction du dialogue, une fente dans cette boîte de dialogue, et accepter la boîte de dialogue s'il n'y a pas de fil en cours d'exécution:

if (QThreadPool::globalInstance()->activeThreadCount() == 0) 
    accept(); 

puis dans MainWindow :: closeEvent:

void MainWindow::closeEvent(QCloseEvent *event) { 
    WaitDialog dlg; 
    dlg.exec(); 
    event->accept(); 
} 
+0

Si je sous-classe QRunnable/QThread pour les tâches, est-il possible 'annuler' les discussions? –

+0

Si vous sous-classez QThread, vous pouvez utiliser QThread :: terminate, bien que la documentation indique qu'il est potentiellement dangereux, car le thread en cours d'exécution ne pourra pas effectuer de nettoyage. – user2155932