IlmThread.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. //
  2. // SPDX-License-Identifier: BSD-3-Clause
  3. // Copyright (c) Contributors to the OpenEXR Project.
  4. //
  5. #ifndef INCLUDED_ILM_THREAD_H
  6. #define INCLUDED_ILM_THREAD_H
  7. //-----------------------------------------------------------------------------
  8. //
  9. // class Thread
  10. //
  11. // Class Thread is a portable interface to a system-dependent thread
  12. // primitive. In order to make a thread actually do something useful,
  13. // you must derive a subclass from class Thread and implement the
  14. // run() function. If the operating system supports threading then
  15. // the run() function will be executed int a new thread.
  16. //
  17. // The actual creation of the thread is done by the start() routine
  18. // which then calls the run() function. In general the start()
  19. // routine should be called from the constructor of the derived class.
  20. //
  21. // The base-class thread destructor will join/destroy the thread.
  22. //
  23. // IMPORTANT: Due to the mechanisms that encapsulate the low-level
  24. // threading primitives in a C++ class there is a race condition
  25. // with code resembling the following:
  26. //
  27. // {
  28. // WorkerThread myThread;
  29. // } // myThread goes out of scope, is destroyed
  30. // // and the thread is joined
  31. //
  32. // The race is between the parent thread joining the child thread
  33. // in the destructor of myThread, and the run() function in the
  34. // child thread. If the destructor gets executed first then run()
  35. // will be called with an invalid "this" pointer.
  36. //
  37. // This issue can be fixed by using a Semaphore to keep track of
  38. // whether the run() function has already been called. You can
  39. // include a Semaphore member variable within your derived class
  40. // which you post() on in the run() function, and wait() on in the
  41. // destructor before the thread is joined. Alternatively you could
  42. // do something like this:
  43. //
  44. // Semaphore runStarted;
  45. //
  46. // void WorkerThread::run ()
  47. // {
  48. // runStarted.post()
  49. // // do some work
  50. // ...
  51. // }
  52. //
  53. // {
  54. // WorkerThread myThread;
  55. // runStarted.wait (); // ensure that we have started
  56. // // the run function
  57. // } // myThread goes out of scope, is destroyed
  58. // // and the thread is joined
  59. //
  60. //-----------------------------------------------------------------------------
  61. #include "IlmThreadConfig.h"
  62. #include "IlmThreadExport.h"
  63. #include "IlmThreadNamespace.h"
  64. #if ILMTHREAD_THREADING_ENABLED
  65. #include <thread>
  66. #endif
  67. ILMTHREAD_INTERNAL_NAMESPACE_HEADER_ENTER
  68. //
  69. // Query function to determine if the current platform supports
  70. // threads AND this library was compiled with threading enabled.
  71. //
  72. ILMTHREAD_EXPORT bool supportsThreads ();
  73. class ILMTHREAD_EXPORT_TYPE Thread
  74. {
  75. public:
  76. ILMTHREAD_EXPORT Thread ();
  77. ILMTHREAD_EXPORT virtual ~Thread ();
  78. ILMTHREAD_EXPORT void start ();
  79. virtual void run () = 0;
  80. //
  81. // wait for thread to exit - must be called before deleting thread
  82. //
  83. ILMTHREAD_EXPORT void join();
  84. ILMTHREAD_EXPORT bool joinable() const;
  85. private:
  86. #if ILMTHREAD_THREADING_ENABLED
  87. std::thread _thread;
  88. #endif
  89. Thread &operator= (const Thread& t) = delete;
  90. Thread &operator= (Thread&& t) = delete;
  91. Thread (const Thread& t) = delete;
  92. Thread (Thread&& t) = delete;
  93. };
  94. ILMTHREAD_INTERNAL_NAMESPACE_HEADER_EXIT
  95. #endif // INCLUDED_ILM_THREAD_H