replay: fix hangling on shutdown while downloading.
diff --git a/selfdrive/ui/replay/route.cc b/selfdrive/ui/replay/route.cc
index a7aa4a28e63185..6d2eff18ae5b64 100644
--- a/selfdrive/ui/replay/route.cc
+++ b/selfdrive/ui/replay/route.cc
@@ -4,7 +4,6 @@
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QRegExp>
-#include <QtConcurrent>
 
 #include "selfdrive/hardware/hw.h"
 #include "selfdrive/ui/qt/api.h"
@@ -108,15 +107,17 @@ Segment::Segment(int n, const SegmentFile &files, bool load_dcam, bool load_ecam
   for (int i = 0; i < std::size(file_list); i++) {
     if (!file_list[i].isEmpty()) {
       loading_++;
-      synchronizer_.addFuture(QtConcurrent::run(this, &Segment::loadFile, i, file_list[i].toStdString()));
+      loading_threads_.emplace_back(QThread::create(&Segment::loadFile, this, i, file_list[i].toStdString()))->start();
     }
   }
 }
 
 Segment::~Segment() {
   aborting_ = true;
-  synchronizer_.setCancelOnWait(true);
-  synchronizer_.waitForFinished();
+  for (QThread *t : loading_threads_) {
+    if (t->isRunning()) t->wait();
+    delete t;
+  }
 }
 
 void Segment::loadFile(int id, const std::string file) {
diff --git a/selfdrive/ui/replay/route.h b/selfdrive/ui/replay/route.h
index c4ab0cd2a37b02..80d275f6d3570f 100644
--- a/selfdrive/ui/replay/route.h
+++ b/selfdrive/ui/replay/route.h
@@ -1,7 +1,7 @@
 #pragma once
 
 #include <QDir>
-#include <QFutureSynchronizer>
+#include <QThread>
 
 #include "selfdrive/common/util.h"
 #include "selfdrive/ui/replay/framereader.h"
@@ -57,5 +57,5 @@ class Segment : public QObject {
 
   std::atomic<bool> success_ = true, aborting_ = false;
   std::atomic<int> loading_ = 0;
-  QFutureSynchronizer<void> synchronizer_;
+  std::list<QThread*> loading_threads_;
 };

QFuture/QtConcurrent will block the qApp->exit() until it finishes executing. `aborting_ = true` in` Segment::~Segment() `will not be called before downloading finished.