aboutsummaryrefslogtreecommitdiffstats
path: root/src/core/thread/Task.cpp
diff options
context:
space:
mode:
authorsaturneric <[email protected]>2023-10-16 21:08:57 +0000
committersaturneric <[email protected]>2023-10-16 21:08:57 +0000
commitcc35ceff23accb44e25dfc47dae920f578836804 (patch)
tree02851ce7e8c2dac0d1492f58c9aed08aa2da2572 /src/core/thread/Task.cpp
parentrefactor: use c++17 features and piml tech to rewrite DataObject and Task (diff)
downloadGpgFrontend-cc35ceff23accb44e25dfc47dae920f578836804.tar.gz
GpgFrontend-cc35ceff23accb44e25dfc47dae920f578836804.zip
fix: solve compile and link issues
Diffstat (limited to 'src/core/thread/Task.cpp')
-rw-r--r--src/core/thread/Task.cpp212
1 files changed, 209 insertions, 3 deletions
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp
index cc6a38b8..1da18a86 100644
--- a/src/core/thread/Task.cpp
+++ b/src/core/thread/Task.cpp
@@ -28,12 +28,216 @@
#include "core/thread/Task.h"
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include <boost/uuid/uuid_io.hpp>
#include <memory>
-#include "TaskImpl.hpp"
-
namespace GpgFrontend::Thread {
+class Task::Impl : public QObject {
+ Q_OBJECT
+
+ public:
+ Impl(Task *parent, std::string name)
+ : parent_(parent), uuid_(generate_uuid()), name_(name) {
+ SPDLOG_TRACE("task {} created", GetFullID());
+ init();
+ }
+
+ Impl(Task *parent, TaskRunnable runnable, std::string name,
+ DataObjectPtr data_object, bool sequency)
+ : parent_(parent),
+ uuid_(generate_uuid()),
+ name_(name),
+ runnable_(std::move(runnable)),
+ callback_(std::move([](int, const DataObjectPtr &) {})),
+ callback_thread_(QThread::currentThread()),
+ data_object_(data_object),
+ sequency_(sequency) {
+ SPDLOG_TRACE("task {} created with runnable, callback_thread_: {}",
+ GetFullID(), static_cast<void *>(callback_thread_));
+ init();
+ }
+
+ Impl(Task *parent, TaskRunnable runnable, std::string name,
+ DataObjectPtr data_object, TaskCallback callback, bool sequency)
+ : parent_(parent),
+ uuid_(generate_uuid()),
+ name_(name),
+ runnable_(std::move(runnable)),
+ callback_(std::move(callback)),
+ callback_thread_(QThread::currentThread()),
+ data_object_(data_object),
+ sequency_(sequency) {
+ init();
+ SPDLOG_TRACE(
+ "task {} created with runnable and callback, callback_thread_: {}",
+ GetFullID(), static_cast<void *>(callback_thread_));
+ }
+
+ ~Impl() { SPDLOG_TRACE("task {} destroyed", GetFullID()); }
+
+ /**
+ * @brief
+ *
+ * @return std::string
+ */
+ std::string GetFullID() const { return uuid_ + "/" + name_; }
+
+ std::string GetUUID() const { return uuid_; }
+
+ bool GetSequency() const { return sequency_; }
+
+ void Run() {
+ if (runnable_) {
+ SetRTN(runnable_(data_object_));
+ } else {
+ SPDLOG_WARN("no runnable in task, do callback operation");
+ }
+ }
+
+ /**
+ * @brief Set the Finish After Run object
+ *
+ * @param finish_after_run
+ */
+ void HoldOnLifeCycle(bool hold_on) {
+ this->run_callback_after_runnable_finished_ = !hold_on;
+ }
+
+ /**
+ * @brief
+ *
+ * @param rtn
+ */
+ void SetRTN(int rtn) { this->rtn_ = rtn; }
+
+ /**
+ * @brief
+ *
+ */
+ void RunnableInterfaceRun() {
+ SPDLOG_TRACE("task {} starting", GetFullID());
+
+ // build runnable package for running
+ auto runnable_package = [=, id = GetFullID()]() {
+ SPDLOG_DEBUG("task {} runnable start runing", id);
+ // Run() will set rtn by itself
+ Run();
+ // raise signal to anounce after runnable returned
+ if (run_callback_after_runnable_finished_)
+ emit parent_->SignalTaskRunnableEnd(rtn_);
+ };
+
+ if (thread() != QThread::currentThread()) {
+ SPDLOG_DEBUG("task running thread is not object living thread");
+ // if running sequently
+ if (sequency_) {
+ // running in another thread, blocking until returned
+ if (!QMetaObject::invokeMethod(thread(), runnable_package,
+ Qt::BlockingQueuedConnection)) {
+ SPDLOG_ERROR("qt invoke method failed");
+ }
+ } else {
+ // running in another thread, non-blocking
+ if (!QMetaObject::invokeMethod(thread(), runnable_package)) {
+ SPDLOG_ERROR("qt invoke method failed");
+ }
+ }
+ } else {
+ if (!QMetaObject::invokeMethod(this, runnable_package)) {
+ SPDLOG_ERROR("qt invoke method failed");
+ }
+ }
+ }
+
+ public slots:
+
+ /**
+ * @brief
+ *
+ */
+ void SlotRun() { RunnableInterfaceRun(); }
+
+ private:
+ Task *parent_;
+ const std::string uuid_;
+ const std::string name_;
+ const bool sequency_ = true; ///< must run in the same thread
+ TaskCallback callback_; ///<
+ TaskRunnable runnable_; ///<
+ bool run_callback_after_runnable_finished_ = true; ///<
+ int rtn_ = 0; ///<
+ QThread *callback_thread_ = nullptr; ///<
+ DataObjectPtr data_object_ = nullptr; ///<
+
+ void init() {
+ // after runnable finished, running callback
+ connect(parent_, &Task::SignalTaskRunnableEnd, this,
+ &Impl::slot_task_run_callback);
+ }
+
+ /**
+ * @brief
+ *
+ * @return std::string
+ */
+ std::string generate_uuid() {
+ return boost::uuids::to_string(boost::uuids::random_generator()());
+ }
+
+ private slots:
+
+ /**
+ * @brief
+ *
+ */
+ void slot_task_run_callback(int rtn) {
+ SPDLOG_TRACE("task runnable {} finished, rtn: {}", GetFullID(), rtn);
+ // set return value
+ this->SetRTN(rtn);
+
+ try {
+ if (callback_) {
+ if (callback_thread_ == QThread::currentThread()) {
+ SPDLOG_DEBUG("callback thread is the same thread");
+ if (!QMetaObject::invokeMethod(callback_thread_,
+ [callback = callback_, rtn = rtn_,
+ &data_object = data_object_, this]() {
+ callback(rtn, data_object);
+ // do cleaning work
+ emit parent_->SignalTaskEnd();
+ })) {
+ SPDLOG_ERROR("failed to invoke callback");
+ }
+ // just finished, let callack thread to raise SignalTaskEnd
+ return;
+ } else {
+ // waiting for callback to finish
+ if (!QMetaObject::invokeMethod(
+ callback_thread_,
+ [callback = callback_, rtn = rtn_,
+ data_object = data_object_]() {
+ callback(rtn, data_object);
+ },
+ Qt::BlockingQueuedConnection)) {
+ SPDLOG_ERROR("failed to invoke callback");
+ }
+ }
+ }
+ } catch (std::exception &e) {
+ SPDLOG_ERROR("exception caught: {}", e.what());
+ } catch (...) {
+ SPDLOG_ERROR("unknown exception caught");
+ }
+
+ // raise signal, announcing this task come to an end
+ SPDLOG_DEBUG("task {}, starting calling signal SignalTaskEnd", GetFullID());
+ emit parent_->SignalTaskEnd();
+ }
+};
+
const std::string DEFAULT_TASK_NAME = "unnamed-task";
Task::Task(std::string name) : p_(std::make_unique<Impl>(this, name)) {}
@@ -70,4 +274,6 @@ void Task::Run() { p_->Run(); }
void Task::run() { p_->RunnableInterfaceRun(); }
-} // namespace GpgFrontend::Thread \ No newline at end of file
+} // namespace GpgFrontend::Thread
+
+#include "Task.moc" \ No newline at end of file