AsyncTask.hpp 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #pragma once
  2. #include "Program.hpp"
  3. #include <thread>
  4. #include <future>
  5. #include <mutex>
  6. namespace QuickMedia {
  7. template <class T, class... Args>
  8. class AsyncTask {
  9. public:
  10. using CallbackFunc = std::function<T(Args&&... args)>;
  11. AsyncTask() = default;
  12. AsyncTask(CallbackFunc callback_func, Args&&... args) {
  13. std::lock_guard<std::mutex> lock(mutex);
  14. std::promise<T> promise;
  15. future = promise.get_future();
  16. thread = std::thread(&AsyncTask::thread_handler, this, std::move(promise), std::move(callback_func), std::forward<Args>(args)...);
  17. }
  18. AsyncTask(AsyncTask &&other) noexcept {
  19. cancel();
  20. std::lock_guard<std::mutex> lock(mutex);
  21. thread = std::move(other.thread);
  22. future = std::move(other.future);
  23. }
  24. AsyncTask& operator=(AsyncTask &&other) noexcept {
  25. cancel();
  26. std::lock_guard<std::mutex> lock(mutex);
  27. thread = std::move(other.thread);
  28. future = std::move(other.future);
  29. return *this;
  30. }
  31. ~AsyncTask() {
  32. cancel();
  33. }
  34. bool valid() {
  35. std::lock_guard<std::mutex> lock(mutex);
  36. return future.valid();
  37. }
  38. bool ready() {
  39. std::lock_guard<std::mutex> lock(mutex);
  40. return future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
  41. }
  42. T get() {
  43. std::lock_guard<std::mutex> lock(mutex);
  44. if constexpr(std::is_same<T, void>::value) {
  45. if(thread.joinable()) {
  46. thread.join();
  47. future.get();
  48. }
  49. } else {
  50. T result = T();
  51. if(thread.joinable()) {
  52. thread.join();
  53. result = std::move(future.get());
  54. }
  55. return result;
  56. }
  57. }
  58. void cancel() {
  59. std::lock_guard<std::mutex> lock(mutex);
  60. if(future.valid()) {
  61. program_kill_in_thread(thread.get_id());
  62. if(thread.joinable()) {
  63. thread.join();
  64. future.get();
  65. }
  66. }
  67. }
  68. private:
  69. void thread_handler(std::promise<T> &&promise, CallbackFunc callback_func, Args&&... args) {
  70. if constexpr(std::is_same<T, void>::value) {
  71. callback_func(std::forward<Args>(args)...);
  72. promise.set_value();
  73. } else {
  74. promise.set_value(callback_func(std::forward<Args>(args)...));
  75. }
  76. }
  77. private:
  78. std::thread thread;
  79. std::future<T> future;
  80. std::mutex mutex;
  81. };
  82. }