winapp_thread.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. //
  2. // detail/winapp_thread.hpp
  3. // ~~~~~~~~~~~~~~~~~~~~~~~~
  4. //
  5. // Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. //
  10. #ifndef BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP
  11. #define BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. # pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <boost/asio/detail/config.hpp>
  16. #if defined(BOOST_ASIO_WINDOWS) && defined(BOOST_ASIO_WINDOWS_APP)
  17. #include <boost/asio/detail/memory.hpp>
  18. #include <boost/asio/detail/socket_types.hpp>
  19. #include <boost/asio/detail/throw_error.hpp>
  20. #include <boost/asio/error.hpp>
  21. #include <boost/asio/detail/push_options.hpp>
  22. namespace boost {
  23. namespace asio {
  24. namespace detail {
  25. DWORD WINAPI winapp_thread_function(LPVOID arg);
  26. class winapp_thread
  27. {
  28. public:
  29. // Construct in a non-joinable state.
  30. winapp_thread() noexcept
  31. : arg_(0)
  32. {
  33. }
  34. // Constructor.
  35. template <typename Function>
  36. winapp_thread(Function f, unsigned int = 0)
  37. : winapp_thread(std::allocator_arg, std::allocator<void>(), f)
  38. {
  39. }
  40. // Construct with custom allocator.
  41. template <typename Allocator, typename Function>
  42. winapp_thread(allocator_arg_t, const Allocator& a,
  43. Function f, unsigned int = 0)
  44. : arg_(start_thread(allocate_object<func<Function, Allocator>>(a, f, a)))
  45. {
  46. }
  47. // Move constructor.
  48. winapp_thread(winapp_thread&& other) noexcept
  49. : arg_(other.arg_)
  50. {
  51. other.arg_ = 0;
  52. }
  53. // Destructor.
  54. ~winapp_thread()
  55. {
  56. if (arg_)
  57. std::terminate();
  58. }
  59. // Move assignment.
  60. winapp_thread& operator=(winapp_thread&& other) noexcept
  61. {
  62. arg_ = other.arg_;
  63. other.arg_ = 0;
  64. return *this;
  65. }
  66. // Whether the thread can be joined.
  67. bool joinable() const
  68. {
  69. return !!arg_;
  70. }
  71. // Wait for the thread to exit.
  72. void join()
  73. {
  74. if (arg_)
  75. ::WaitForSingleObjectEx(arg_->thread_, INFINITE, false);
  76. }
  77. // Get number of CPUs.
  78. static std::size_t hardware_concurrency()
  79. {
  80. SYSTEM_INFO system_info;
  81. ::GetNativeSystemInfo(&system_info);
  82. return system_info.dwNumberOfProcessors;
  83. }
  84. private:
  85. friend DWORD WINAPI winapp_thread_function(LPVOID arg);
  86. class func_base
  87. {
  88. public:
  89. virtual ~func_base() {}
  90. virtual void run() = 0;
  91. virtual void destroy() = 0;
  92. ::HANDLE thread_;
  93. };
  94. template <typename Function, typename Allocator>
  95. class func
  96. : public func_base
  97. {
  98. public:
  99. func(Function f, const Allocator& a)
  100. : f_(f),
  101. allocator_(a)
  102. {
  103. }
  104. virtual void run()
  105. {
  106. f_();
  107. }
  108. virtual void destroy()
  109. {
  110. deallocate_object(allocator_, this);
  111. }
  112. private:
  113. Function f_;
  114. Allocator allocator_;
  115. };
  116. func_base* start_thread(func_base* arg)
  117. {
  118. DWORD thread_id = 0;
  119. arg->thread_ = ::CreateThread(0, 0,
  120. winapp_thread_function, arg, 0, &thread_id);
  121. if (!arg->thread_)
  122. {
  123. arg->destroy();
  124. DWORD last_error = ::GetLastError();
  125. boost::system::error_code ec(last_error,
  126. boost::asio::error::get_system_category());
  127. boost::asio::detail::throw_error(ec, "thread");
  128. }
  129. return arg;
  130. }
  131. func_base* arg_;
  132. };
  133. inline DWORD WINAPI winapp_thread_function(LPVOID arg)
  134. {
  135. static_cast<winapp_thread::func_base*>(arg)->run();
  136. return 0;
  137. }
  138. } // namespace detail
  139. } // namespace asio
  140. } // namespace boost
  141. #include <boost/asio/detail/pop_options.hpp>
  142. #endif // defined(BOOST_ASIO_WINDOWS) && defined(UNDER_CE)
  143. #endif // BOOST_ASIO_DETAIL_WINAPP_THREAD_HPP