ThreadHelper.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #ifndef THREADHELPER_H
  9. #define THREADHELPER_H
  10. #if !defined(Q_MOC_RUN)
  11. #include <QObject>
  12. #include <QMutex>
  13. #include <QMetaObject>
  14. #include <QWaitCondition>
  15. #include <functional>
  16. #include <QThread>
  17. #include <AzCore/Memory/SystemAllocator.h>
  18. #include <AzCore/std/functional.h>
  19. #endif
  20. // the Thread Helper exists to make it very easy to create a Qt object
  21. // inside a thread, in such a way that the entire construction of the object
  22. // occurs inside the thread.
  23. // we do this by allowing you to specify a factory function that creates your object
  24. // and we arrange to call it on the newly created thread, so that from the very moment
  25. // your object exists, its already on its thread. This is important because Qt objects
  26. // set their thread ownership on create, and if your objects have sub-objects or child objects
  27. // that are members, its important that they too are on the same thread.
  28. // to use this system, use a thread Controller object and call initialize.
  29. // initialize on the Thread Controller automatically blocks until your object is created on the
  30. // target thread and returns your new object, allowing you to then connect signals and slots.
  31. // to clean up, just call destroy().
  32. namespace AssetProcessor
  33. {
  34. AZ::s64 GetThreadLocalJobId();
  35. void SetThreadLocalJobId(AZ::s64 jobId);
  36. class ThreadWorker
  37. : public QObject
  38. {
  39. Q_OBJECT
  40. public:
  41. AZ_CLASS_ALLOCATOR(ThreadWorker, AZ::SystemAllocator)
  42. explicit ThreadWorker(QObject* parent = 0)
  43. : QObject(parent)
  44. {
  45. m_runningThread = new QThread();
  46. }
  47. virtual ~ThreadWorker(){}
  48. //! Destroy function not only stops the running thread
  49. //! but also deletes the ThreadWorker object
  50. void Destroy()
  51. {
  52. // We are calling deletelater() before quiting the thread
  53. // because deletelater will only schedule the object for deletion
  54. // if the thread is running
  55. QThread* threadptr = m_runningThread;
  56. deleteLater();
  57. threadptr->quit();
  58. threadptr->wait();
  59. delete threadptr;
  60. }
  61. Q_SIGNALS:
  62. public Q_SLOTS:
  63. void RunInThread()
  64. {
  65. create();
  66. }
  67. protected:
  68. virtual void create() = 0;
  69. QMutex m_waitConditionMutex;
  70. QWaitCondition m_waitCondition;
  71. QThread* m_runningThread;
  72. };
  73. //! This class helps in creating an instance of the templated
  74. //! QObject class in a new thread.
  75. //! Intialize is a blocking call and than will only return with a pointer to the
  76. //! new object only after the object is created in the new thread.
  77. //! Please note that each instance of this class has to be dynamically allocated.
  78. template<typename T>
  79. class ThreadController
  80. : public ThreadWorker
  81. {
  82. public:
  83. AZ_CLASS_ALLOCATOR(ThreadController<T>, AZ::SystemAllocator)
  84. typedef AZStd::function<T* ()> FactoryFunctionType;
  85. ThreadController()
  86. : ThreadWorker()
  87. {
  88. m_runningThread->setObjectName(T::staticMetaObject.className());
  89. m_runningThread->start();
  90. this->moveToThread(m_runningThread);
  91. }
  92. virtual ~ThreadController()
  93. {
  94. }
  95. T* initialize(FactoryFunctionType callback = nullptr)
  96. {
  97. m_function = callback;
  98. m_waitConditionMutex.lock();
  99. QMetaObject::invokeMethod(this, "RunInThread", Qt::QueuedConnection);
  100. m_waitCondition.wait(&m_waitConditionMutex);
  101. m_waitConditionMutex.unlock();
  102. return m_instance;
  103. }
  104. virtual void create() override
  105. {
  106. if (m_function)
  107. {
  108. m_instance = m_function();
  109. }
  110. m_waitCondition.wakeOne();
  111. }
  112. private:
  113. T* m_instance;
  114. FactoryFunctionType m_function;
  115. };
  116. }
  117. #endif // THREADHELPER_H