Sciter: F:/hsmile5/sdk/include/sciter-x-threads.h Source File

Sciter  3.3.2.5
Sciter API
sciter-x-threads.h
Go to the documentation of this file.
1 /*
2  * The Sciter Engine of Terra Informatica Software, Inc.
3  * http://sciter.com
4  *
5  * The code and information provided "as-is" without
6  * warranty of any kind, either expressed or implied.
7  *
8  * (C) 2003-2015, Terra Informatica Software, Inc.
9  */
10 
11 /*
12  * Asynchronous GUI Task Queue.
13  * Use these primitives when you need to run code in GUI thread.
14  */
15 
16 
17 #if !defined(__SCITER_THREADS_H__)
18 #define __SCITER_THREADS_H__
19 
20 #if defined(WINDOWS)
21  #include <specstrings.h>
22  #include <windows.h>
23  #include <stdio.h>
24  #include <assert.h>
25  #include <functional>
26 
27  #ifndef THIS_HINSTANCE
28  EXTERN_C IMAGE_DOS_HEADER __ImageBase;
29  #define THIS_HINSTANCE ((HINSTANCE)&__ImageBase)
30  #endif
31 
32 
33  namespace sciter {
34 
35  namespace sync {
36 
37  class mutex
38  {
39  CRITICAL_SECTION cs;
40  public:
41  void lock() { EnterCriticalSection(&cs); }
42  void unlock() { LeaveCriticalSection(&cs); }
43  mutex() { InitializeCriticalSection(&cs); }
44  ~mutex() { DeleteCriticalSection(&cs); }
45  };
46 
47  class critical_section {
48  mutex& m;
49  public:
50  critical_section(mutex& guard) : m(guard) { m.lock(); }
51  ~critical_section() { m.unlock(); }
52  };
53 
54  struct event
55  {
56  HANDLE h;
57  event() { h = CreateEvent(NULL, FALSE, FALSE, NULL); }
58  ~event() { CloseHandle(h); }
59  void signal() { SetEvent(h); }
60  bool wait(unsigned int ms = INFINITE) { return WaitForSingleObject(h, ms) == WAIT_OBJECT_0; }
61  private:
62  event( const event& );
63  event& operator=( const event& );
64  };
65 
66  inline void yield() { Sleep(0); }
67  inline void sleep(unsigned ms) { Sleep(ms); }
68 
69  class gui_thread_ctx
70  {
71  HHOOK _hook;
72 
73  typedef std::function<void(void)> gui_block;
74 
75  static DWORD thread_id()
76  {
77  static DWORD _thread_id = ::GetCurrentThreadId();
78  return _thread_id;
79  }
80  static UINT message()
81  {
82  static UINT _message = ::RegisterWindowMessage( TEXT("GUI-THREAD-EXEC_RQ"));
83  return _message;
84  }
85 
86  void install_hook()
87  {
88  message(); // force message to be registered
89  // setup the WH_GETMESSAGE hook.
90  // Using hooks here allows this mechanism to work even under modal dialogs.
91  _hook = ::SetWindowsHookEx(WH_GETMESSAGE,&exec_hook,THIS_HINSTANCE, thread_id());
92  }
93  void release_hook()
94  {
95  if(_hook) ::UnhookWindowsHookEx(_hook);
96  }
97 
98  // message hook to handle WM_EXEC in GUI thread
99  static LRESULT CALLBACK exec_hook(int code, WPARAM wParam, LPARAM lParam )
100  {
101  MSG* pmsg = reinterpret_cast<MSG*>(lParam);
102  if(wParam == PM_REMOVE && pmsg->message == message())
103  {
104  event* pe = reinterpret_cast<sciter::sync::event*>(pmsg->wParam);
105  gui_block* pf = reinterpret_cast<gui_block*>(pmsg->lParam);
106  (*pf)(); // execute the block in this GUI thread
107  pe->signal(); // signal that we've done with it
108  // this will resume execution of worker thread.
109  }
110  return CallNextHookEx(0,code, wParam,lParam);
111  }
112 
113  public:
114  gui_thread_ctx() { install_hook(); }
115  ~gui_thread_ctx() { release_hook(); }
116 
117  // this function is called from worker threads to
118  // execute the gui_block in GUI thread
119  static void exec( gui_block code )
120  {
121  event evt;
122  PostThreadMessage(thread_id(), message(), WPARAM(&evt),LPARAM(&code));
123  evt.wait(); // suspend worker thread until GUI will execute the block.
124  }
125 
126  };
127 
128  #define GUI_CODE_START sciter::sync::gui_thread_ctx::exec([&]() {
129  #define GUI_CODE_END });
130 
131  }
132 
133  template<typename F, typename P>
134  class thread_ctx
135  {
136  F _f;
137  P _p;
138  static DWORD WINAPI ThreadProc(LPVOID lpData)
139  {
140  thread_ctx* self = reinterpret_cast<thread_ctx*>(lpData);
141  try {
142  self->_f(self->_p);
143  }
144  catch(...) {
145  assert(false);
146  }
147  delete self;
148  return 0;
149  }
150  thread_ctx(const F& f, const P& p): _f(f),_p(p) {
151 
152  DWORD dwThreadID;
153  HANDLE hThread = ::CreateThread(NULL, 0, ThreadProc, this, 0, &dwThreadID);
154  assert(hThread != NULL);
155  ::CloseHandle(hThread);
156  }
157  public:
158  static void start( const F& f, const P& p )
159  {
160  new thread_ctx<F,P>(f,p);
161  }
162  };
163 
164  template<typename F, typename P>
165  inline void thread( F f, P p )
166  {
167  thread_ctx<F,P>::start(f,p);
168  }
169 
170  }
171 
172 #else
173 
174  #include <mutex>
175  #include <condition_variable>
176  #include <thread>
177  #include <chrono>
178 
179  namespace sciter {
180 
181   namespace sync {
182 
183   class mutex :public std::recursive_mutex
184  {
185   friend class event;
186  typedef std::recursive_mutex super;
187  mutex( const mutex& ) = delete;
188  mutex& operator=(const mutex&) = delete;
189  public:
190   mutex():super() {}
191  //void lock() { super::lock(); }
192  //void unlock() { super::unlock(); }
193  };
194 
195   class critical_section: public std::lock_guard<mutex>
196  {
197  typedef std::lock_guard<mutex> super;
198  critical_section(const critical_section& rs) = delete;
199  critical_section& operator=(const critical_section&) = delete;
200 
201  public:
202   critical_section(mutex& m) : super(m) {}
203   ~critical_section() {}
204  };
205 
206   class event
207  {
208  //typedef std::condition_variable super;
209  event( const event& ) = delete;
210  event& operator=(const event&) = delete;
211 
212  std::condition_variable_any _var;
213  std::mutex _mtx;
214  public:
215   event() {}
216   void signal() {
217  _var.notify_one();
218  }
219   void wait(mutex& m) {
220  std::unique_lock<mutex> lock(m);
221  _var.wait(lock);
222  }
223   void wait(unsigned int ms = unsigned(-1)) {
224  std::unique_lock<std::mutex> lock(_mtx);
225  if( ms == unsigned(-1) )
226  _var.wait(lock);
227  else
228  _var.wait_for(lock, std::chrono::milliseconds(ms));
229  }
230 
231  };
232 
233   inline void sleep(uint ms) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); }
234   inline void yield() { std::this_thread::yield(); }
235 
236  }
237  template<typename F, typename P>
238   inline void thread( F f, P p )
239  {
240  new std::thread(f,p); // will leak the instance?
241  }
242 
243  }
244 
245 #endif
246 
247 #endif // __SCITER_THREADS_H__
void sleep(uint ms)
void wait(mutex &m)
friend class event
void wait(unsigned int ms=unsigned(-1))
void thread(F f, P p)
#define EXTERN_C

AltStyle によって変換されたページ (->オリジナル) /