[vlc-devel] [PATCH] qt: medialib: add async task handle

Romain Vimont rom1v at videolabs.io
Wed Jan 6 14:55:38 UTC 2021


Use a smart pointer to "abandon" an AsyncTask using RAII. This avoids to
forget to call abandon() on client destruction.
---
 modules/gui/qt/util/asynctask.hpp | 22 +++++++++++++++++++
 modules/gui/qt/util/listcache.hpp | 36 +++++++++----------------------
 2 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/modules/gui/qt/util/asynctask.hpp b/modules/gui/qt/util/asynctask.hpp
index fa4a6d3b2c..81fcc54022 100644
--- a/modules/gui/qt/util/asynctask.hpp
+++ b/modules/gui/qt/util/asynctask.hpp
@@ -128,6 +128,9 @@
  * to declare that it won't use it anymore (and don't want the result). When
  * both conditions are met, the task is deleted via `QObject::deleteLater()`.
  *
+ * For convenience, a `TaskHandle` smart pointer is provided to call
+ * `abandon()` using RAII.
+ *
  * The task result is provided via a separate method `takeResult()` instead of
  * a slot parameter, because otherwise, Qt would require its type to be:
  *  - non-template (like `std::vector<T>`),
@@ -243,4 +246,23 @@ private:
     AsyncTask<T> *m_task;
 };
 
+template <typename T>
+struct TaskDeleter
+{
+    void operator()(T *task) { task->abandon(); }
+};
+
+/**
+ * Task handle to abandon() a task using RAII
+ *
+ * It behaves like a unique_ptr, but its deleter calls AsyncTask<T>::abandon(),
+ * which indicates that the client cancels the task and requests deletion when
+ * possible.
+ *
+ * The actual deletion may happen later (when the runnable also finished its
+ * work).
+ */
+template <typename T>
+using TaskHandle = std::unique_ptr<T, TaskDeleter<T>>;
+
 #endif
diff --git a/modules/gui/qt/util/listcache.hpp b/modules/gui/qt/util/listcache.hpp
index e92b7d84df..20fa510832 100644
--- a/modules/gui/qt/util/listcache.hpp
+++ b/modules/gui/qt/util/listcache.hpp
@@ -115,7 +115,6 @@ public:
         : m_threadPool(threadPool)
         , m_loader(loader)
         , m_chunkSize(chunkSize) {}
-    ~ListCache();
 
     /**
      * Return the item at specified index
@@ -167,19 +166,10 @@ private:
     bool m_countRequested = false;
     MLRange m_lastRangeRequested;
 
-    LoadTask<T> *m_loadTask = nullptr;
-    CountTask<T> *m_countTask = nullptr;
+    TaskHandle<LoadTask<T>> m_loadTask;
+    TaskHandle<CountTask<T>> m_countTask;
 };
 
-template <typename T>
-ListCache<T>::~ListCache()
-{
-    if (m_countTask)
-        m_countTask->abandon();
-    if (m_loadTask)
-        m_loadTask->abandon();
-}
-
 template <typename T>
 const T *ListCache<T>::get(size_t index) const
 {
@@ -248,8 +238,8 @@ void ListCache<T>::asyncCount()
 {
     assert(!m_countTask);
 
-    m_countTask = new CountTask<T>(m_loader);
-    connect(m_countTask, &BaseAsyncTask::result,
+    m_countTask.reset(new CountTask<T>(m_loader));
+    connect(&*m_countTask, &BaseAsyncTask::result,
             this, &ListCache<T>::onCountResult);
     m_countRequested = true;
     m_countTask->start(m_threadPool);
@@ -259,15 +249,14 @@ template <typename T>
 void ListCache<T>::onCountResult()
 {
     CountTask<T> *task = static_cast<CountTask<T> *>(sender());
-    assert(task == m_countTask);
+    assert(task == &*m_countTask);
 
     m_offset = 0;
     m_list.clear();
     m_total_count = static_cast<ssize_t>(task->takeResult());
     emit localSizeChanged(m_total_count);
 
-    task->abandon();
-    m_countTask = nullptr;
+    m_countTask.reset();
 }
 
 template <typename T>
@@ -298,12 +287,8 @@ private:
 template <typename T>
 void ListCache<T>::asyncLoad(size_t offset, size_t count)
 {
-    if (m_loadTask)
-        /* Cancel any current pending task */
-        m_loadTask->abandon();
-
-    m_loadTask = new LoadTask<T>(m_loader, offset, count);
-    connect(m_loadTask, &BaseAsyncTask::result,
+    m_loadTask.reset(new LoadTask<T>(m_loader, offset, count));
+    connect(&*m_loadTask, &BaseAsyncTask::result,
             this, &ListCache<T>::onLoadResult);
     m_lastRangeRequested = { offset, count };
     m_loadTask->start(m_threadPool);
@@ -313,15 +298,14 @@ template <typename T>
 void ListCache<T>::onLoadResult()
 {
     LoadTask<T> *task = static_cast<LoadTask<T> *>(sender());
-    assert(task == m_loadTask);
+    assert(task == &*m_loadTask);
 
     m_offset = task->m_offset;
     m_list = task->takeResult();
     if (m_list.size())
         emit localDataChanged(m_offset, m_list.size());
 
-    task->abandon();
-    m_loadTask = nullptr;
+    m_loadTask.reset();
 }
 
 #endif
-- 
2.30.0



More information about the vlc-devel mailing list