HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ort_mutex.h
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License.
3 
4 #pragma once
5 #ifdef _WIN32
6 #include <Windows.h>
7 #include <chrono>
8 #include <mutex>
9 namespace onnxruntime {
10 // Q: Why OrtMutex is better than std::mutex
11 // A: OrtMutex supports static initialization but std::mutex doesn't. Static initialization helps us prevent the "static
12 // initialization order problem".
13 
14 // Q: Why std::mutex can't make it?
15 // A: VC runtime has to support Windows XP at ABI level. But we don't have such requirement.
16 
17 // Q: Is OrtMutex faster than std::mutex?
18 // A: Sure
19 
20 class OrtMutex {
21  private:
22  SRWLOCK data_ = SRWLOCK_INIT;
23 
24  public:
25  constexpr OrtMutex() = default;
26  // SRW locks do not need to be explicitly destroyed.
27  ~OrtMutex() = default;
28  OrtMutex(const OrtMutex&) = delete;
29  OrtMutex& operator=(const OrtMutex&) = delete;
30  void lock() { AcquireSRWLockExclusive(native_handle()); }
31  bool try_lock() noexcept { return TryAcquireSRWLockExclusive(native_handle()) == TRUE; }
32  void unlock() noexcept { ReleaseSRWLockExclusive(native_handle()); }
33  using native_handle_type = SRWLOCK*;
34 
35  __forceinline native_handle_type native_handle() { return &data_; }
36 };
37 
38 class OrtCondVar {
39  CONDITION_VARIABLE native_cv_object = CONDITION_VARIABLE_INIT;
40 
41  public:
42  constexpr OrtCondVar() noexcept = default;
43  ~OrtCondVar() = default;
44 
45  OrtCondVar(const OrtCondVar&) = delete;
46  OrtCondVar& operator=(const OrtCondVar&) = delete;
47 
48  void notify_one() noexcept { WakeConditionVariable(&native_cv_object); }
49  void notify_all() noexcept { WakeAllConditionVariable(&native_cv_object); }
50 
51  void wait(std::unique_lock<OrtMutex>& lk) {
52  if (SleepConditionVariableSRW(&native_cv_object, lk.mutex()->native_handle(), INFINITE, 0) != TRUE) {
53  std::terminate();
54  }
55  }
56  template <class _Predicate>
57  void wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred);
58 
59  /**
60  * returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
61  * cv_status::no_timeout.
62  * @param cond_mutex A unique_lock<OrtMutex> object.
63  * @param rel_time A chrono::duration object that specifies the amount of time before the thread wakes up.
64  * @return returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
65  * cv_status::no_timeout
66  */
67  template <class Rep, class Period>
68  std::cv_status wait_for(std::unique_lock<OrtMutex>& cond_mutex, const std::chrono::duration<Rep, Period>& rel_time);
69  using native_handle_type = CONDITION_VARIABLE*;
70 
71  native_handle_type native_handle() { return &native_cv_object; }
72 
73  private:
74  void timed_wait_impl(std::unique_lock<OrtMutex>& __lk,
75  std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>);
76 };
77 
78 template <class _Predicate>
79 void OrtCondVar::wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred) {
80  while (!__pred()) wait(__lk);
81 }
82 
83 template <class Rep, class Period>
84 std::cv_status OrtCondVar::wait_for(std::unique_lock<OrtMutex>& cond_mutex,
85  const std::chrono::duration<Rep, Period>& rel_time) {
86  // TODO: is it possible to use nsync_from_time_point_ ?
87  using namespace std::chrono;
88  if (rel_time <= duration<Rep, Period>::zero())
90  using SystemTimePointFloat = time_point<system_clock, duration<long double, std::nano> >;
91  using SystemTimePoint = time_point<system_clock, nanoseconds>;
92  SystemTimePointFloat max_time = SystemTimePoint::max();
93  steady_clock::time_point steady_now = steady_clock::now();
94  system_clock::time_point system_now = system_clock::now();
95  if (max_time - rel_time > system_now) {
96  nanoseconds remain = duration_cast<nanoseconds>(rel_time);
97  if (remain < rel_time)
98  ++remain;
99  timed_wait_impl(cond_mutex, system_now + remain);
100  } else
101  timed_wait_impl(cond_mutex, SystemTimePoint::max());
102  return steady_clock::now() - steady_now < rel_time ? std::cv_status::no_timeout : std::cv_status::timeout;
103 }
104 } // namespace onnxruntime
105 #else
106 #include "nsync.h"
107 #include <mutex> //for unique_lock
108 #include <condition_variable> //for cv_status
109 namespace onnxruntime {
110 
111 class OrtMutex {
112  nsync::nsync_mu data_ = NSYNC_MU_INIT;
113 
114  public:
115  constexpr OrtMutex() = default;
116  ~OrtMutex() = default;
117  OrtMutex(const OrtMutex&) = delete;
118  OrtMutex& operator=(const OrtMutex&) = delete;
119 
120  void lock() { nsync::nsync_mu_lock(&data_); }
121  bool try_lock() noexcept { return nsync::nsync_mu_trylock(&data_) == 0; }
122  void unlock() noexcept { nsync::nsync_mu_unlock(&data_); }
123 
124  using native_handle_type = nsync::nsync_mu*;
125  native_handle_type native_handle() { return &data_; }
126 };
127 
128 class OrtCondVar {
129  nsync::nsync_cv native_cv_object = NSYNC_CV_INIT;
130 
131  public:
132  constexpr OrtCondVar() noexcept = default;
133 
134  ~OrtCondVar() = default;
135  OrtCondVar(const OrtCondVar&) = delete;
136  OrtCondVar& operator=(const OrtCondVar&) = delete;
137 
138  void notify_one() noexcept { nsync::nsync_cv_signal(&native_cv_object); }
139  void notify_all() noexcept { nsync::nsync_cv_broadcast(&native_cv_object); }
140 
141  void wait(std::unique_lock<OrtMutex>& lk);
142  template <class _Predicate>
143  void wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred);
144 
145  /**
146  * returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
147  * cv_status::no_timeout.
148  * @param cond_mutex A unique_lock<OrtMutex> object.
149  * @param rel_time A chrono::duration object that specifies the amount of time before the thread wakes up.
150  * @return returns cv_status::timeout if the wait terminates when Rel_time has elapsed. Otherwise, the method returns
151  * cv_status::no_timeout
152  */
153  template <class Rep, class Period>
154  std::cv_status wait_for(std::unique_lock<OrtMutex>& cond_mutex, const std::chrono::duration<Rep, Period>& rel_time);
155  using native_handle_type = nsync::nsync_cv*;
156  native_handle_type native_handle() { return &native_cv_object; }
157 
158  private:
159  void timed_wait_impl(std::unique_lock<OrtMutex>& __lk,
160  std::chrono::time_point<std::chrono::system_clock, std::chrono::nanoseconds>);
161 };
162 
163 template <class _Predicate>
164 void OrtCondVar::wait(std::unique_lock<OrtMutex>& __lk, _Predicate __pred) {
165  while (!__pred()) wait(__lk);
166 }
167 
168 template <class Rep, class Period>
169 std::cv_status OrtCondVar::wait_for(std::unique_lock<OrtMutex>& cond_mutex,
170  const std::chrono::duration<Rep, Period>& rel_time) {
171  // TODO: is it possible to use nsync_from_time_point_ ?
172  using namespace std::chrono;
173  if (rel_time <= duration<Rep, Period>::zero())
175  using SystemTimePointFloat = time_point<system_clock, duration<long double, std::nano> >;
176  using SystemTimePoint = time_point<system_clock, nanoseconds>;
177  SystemTimePointFloat max_time = SystemTimePoint::max();
178  steady_clock::time_point steady_now = steady_clock::now();
179  system_clock::time_point system_now = system_clock::now();
180  if (max_time - rel_time > system_now) {
181  nanoseconds remain = duration_cast<nanoseconds>(rel_time);
182  if (remain < rel_time)
183  ++remain;
184  timed_wait_impl(cond_mutex, system_now + remain);
185  } else
186  timed_wait_impl(cond_mutex, SystemTimePoint::max());
187  return steady_clock::now() - steady_now < rel_time ? std::cv_status::no_timeout : std::cv_status::timeout;
188 }
189 }; // namespace onnxruntime
190 #endif
void notify_all() noexcept
Definition: ort_mutex.h:139
native_handle_type native_handle()
Definition: ort_mutex.h:125
native_handle_type native_handle()
Definition: ort_mutex.h:156
constexpr OrtCondVar() noexcept=default
OrtCondVar & operator=(const OrtCondVar &)=delete
constexpr OrtMutex()=default
void unlock() noexcept
Definition: ort_mutex.h:122
nsync::nsync_cv * native_handle_type
Definition: ort_mutex.h:155
nsync::nsync_mu * native_handle_type
Definition: ort_mutex.h:124
GLbitfield GLuint64 timeout
Definition: glcorearb.h:1599
void wait(std::unique_lock< OrtMutex > &lk)
OrtMutex & operator=(const OrtMutex &)=delete
std::cv_status wait_for(std::unique_lock< OrtMutex > &cond_mutex, const std::chrono::duration< Rep, Period > &rel_time)
Definition: ort_mutex.h:169
void notify_one() noexcept
Definition: ort_mutex.h:138
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
bool try_lock() noexcept
Definition: ort_mutex.h:121