PLCnext API Documentation  20.6.0.30321
Thread.hpp
1 //
3 // Copyright PHOENIX CONTACT Electronics GmbH
4 //
6 #pragma once
7 #include "Arp/System/Core/Arp.h"
8 #include "Arp/System/Core/delegate.hxx"
9 #include "Arp/System/Commons/Threading/ThreadSettings.hpp"
10 #include "Arp/System/Commons/Logging.h"
11 #include "Arp/System/Commons/Threading/AutoResetEvent.hpp"
12 #include "Arp/System/Commons/Threading/ThreadState.hpp"
13 #include "Arp/System/Commons/Threading/Semaphore.hpp"
14 
15 #include <atomic>
16 
17 // forwards
18 namespace Arp { namespace System { namespace Ve
19 {
20 class IThreadService;
21 }}}
22 
23 #define ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
24 
25 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
26 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
27 namespace Arp { namespace System { namespace Commons { namespace Threading { namespace Internal
28 {
29 class ThreadEvent;
30 class ThreadEventDeleter
31 {
32 public:
33  void operator()(ThreadEvent*) const;
34 };
35 }}}}}
36 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
37 
38 namespace Arp { namespace System { namespace Commons { namespace Threading
39 {
40 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
41  // forwards
42  class ThreadBinaryCompatibilityExtensions;
43 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
44  using namespace Arp::System::Commons::Threading::Internal;
45 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
46 
91 class Thread : private Loggable<Thread>
92 {
93 private: // friends
94  friend class AutoResetEvent;
95 
96 public: // typedefs/usings
98  typedef void (*ThreadStartFunction)(void*);
99 
101  typedef delegate<void(void*)> ThreadStartDelegate;
102 
104  static const std::size_t CpuAffinityAll;
105 
106 public: // construction/destruction
107 
113  template<class TInstance, class TFunction>
114  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
115  Thread(TInstance& instance, TFunction fn, void* pStartParam = nullptr);
116 
122  template<class TInstance, class TFunction>
123  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
124  Thread(const TInstance& instance, TFunction fn, void* pStartParam = nullptr);
125 
131  template<class TInstance, class TFunction>
132  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
133  Thread(TInstance* pInstance, TFunction fn, void* pStartParam = nullptr);
134 
140  template<class TInstance, class TFunction>
141  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
142  Thread(const TInstance* pInstance, TFunction fn, void* pStartParam = nullptr);
143 
148  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
149  explicit Thread(ThreadStartDelegate&& threadStart, void* pStartParam = nullptr);
150 
159  ARP_DEPRECATED("Use constructor with ThreadSettings instead. Supply at least a thread name!")
160  Thread(ThreadStartFunction threadStart, void* pStartParam = nullptr);
161 
168  template<class TInstance, class TFunction>
169  Thread(const ThreadSettings& settings, TInstance& instance, TFunction fn, void* pStartParam = nullptr);
170 
177  template<class TInstance, class TFunction>
178  Thread(const ThreadSettings& settings, const TInstance& instance, TFunction fn, void* pStartParam = nullptr);
179 
186  template<class TInstance, class TFunction>
187  Thread(const ThreadSettings& settings, TInstance* pInstance, TFunction fn, void* pStartParam = nullptr);
188 
195  template<class TInstance, class TFunction>
196  Thread(const ThreadSettings& settings, const TInstance* pInstance, TFunction fn, void* pStartParam = nullptr);
197 
203  Thread(ThreadSettings& settings, ThreadStartDelegate&& threadStart, void* pStartParam = nullptr);
204 
210  Thread(ThreadSettings& settings, ThreadStartFunction threadStart, void* pStartParam = nullptr);
211 
217  Thread(const ThreadSettings& settings, ThreadStartDelegate&& threadStart, void* pStartParam = nullptr);
218 
224  Thread(const ThreadSettings& settings, ThreadStartFunction threadStart, void* pStartParam = nullptr);
225 
229  ~Thread(void);
230 
231 public: // static operations
232 
235  static void Sleep(size_t milliseconds);
236 
239  static size_t GetCurrentThreadId(void);
240 
243  static Thread* GetCurrentThread(void);
244 
253  static void SetAsynchronousCancelability(bool enable);
254 
255 public: // properties/setter/getter
257  bool IsRunning(void)const;
258 
276  void SetCpuAffinity(size_t mask);
277 
281  size_t GetCpuAffinity(void)const;
282 
286  void SetPriority(size_t value);
287 
290  size_t GetPriority(void)const;
291 
304  ARP_DEPRECATED("Set thread stack size at the constructor")
305  void SetStackSize(size_t value);
306 
309  size_t GetStackSize(void)const;
310 
318  void SetName(const String& value);
319 
322  const String& GetName(void)const;
323 
326  ThreadState GetState() const;
332  bool IsJoinable(void);
333 
334 public: // operations
337  void Start(void);
338 
342  void Join(void);
343 
349  void Interrupt(void);
350 
352  void Terminate(void);
353 
354 private: // typedefs/usings
355  using IThreadService = Arp::System::Ve::IThreadService;
356 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
357 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
358  using ThreadEventPtr = std::unique_ptr<ThreadEvent, ThreadEventDeleter>;
359 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
360 
361 private: // static methods
362  static void* RunInternal(void* pParam);
363  static void CheckInterruptOfCurrentThread(void);
364  static void SetStateOfCurrentThread(ThreadState state);
365  static String CreateDefaultThreadName(void);
366 
367 private: // methods
368  void CreateThreadInternal(void);
369  void CreateThreadInternal(const ThreadSettings& parameter);
370 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
371  void RunThread(ThreadBinaryCompatibilityExtensions* pBinCompat);
372 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
373  void RunThread(void);
374 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
375 
376 private: // deleted methods
377  Thread(const Thread& arg) = delete;
378  Thread& operator=(const Thread& arg) = delete;
379 
380 private: // fields
381  ThreadStartDelegate threadStart;
382  void* pStartParam;
383 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
384  ThreadBinaryCompatibilityExtensions* pBinaryCompatibilityExtensions;
385 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
386  IThreadService* pThreadService;
387 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
388  AutoResetEvent exitEvent;
389  std::atomic<ThreadState> state;
390  std::atomic<bool> interrupting;
391 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
392 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
393  ThreadEventPtr eventWakeupPtr;
394  Semaphore semIsStartable;
395  Semaphore semStart;
396  Semaphore semIsStarted;
397  std::atomic<bool> isActive;
398 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
399 
400 private: // static fields
401  static thread_local Thread* pCurrentThread;
402 };
403 
405 // inline methods of class Thread
406 template<class TInstance, class TFunction>
407 inline Thread::Thread(TInstance& instance, TFunction fn, void* pStartParam)
408  : Thread(&instance, fn, pStartParam)
409 {
410 }
411 
412 template<class TInstance, class TFunction>
413 inline Thread::Thread(const TInstance& instance, TFunction fn, void* pStartParam)
414  : Thread(&instance, fn, pStartParam)
415 {
416 }
417 
418 template<class TInstance, class TFunction>
419 inline Thread::Thread(TInstance* pInstance, TFunction fn, void* pStartParam)
420  : threadStart(make_delegate(pInstance, fn))
421  , pStartParam(pStartParam)
422 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
423  , pBinaryCompatibilityExtensions(nullptr)
424 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
425  , pThreadService(nullptr)
426 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
427  , state(ThreadState::Stopped)
428  , interrupting(false)
429 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
430 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
431  , eventWakeupPtr(nullptr)
432  , semIsStartable(0)
433  , semStart(0)
434  , semIsStarted(0)
435  , isActive(true)
436 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
437 {
438  this->CreateThreadInternal();
439 }
440 
441 template<class TInstance, class TFunction>
442 inline Thread::Thread(const TInstance* pInstance, TFunction fn, void* pStartParam)
443  : threadStart(make_delegate(pInstance, fn))
444  , pStartParam(pStartParam)
445 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
446  , pBinaryCompatibilityExtensions(nullptr)
447 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
448  , pThreadService(nullptr)
449 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
450  , state(ThreadState::Stopped)
451  , interrupting(false)
452 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
453 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
454  , eventWakeupPtr(nullptr)
455  , semIsStartable(0)
456  , semStart(0)
457  , semIsStarted(0)
458  , isActive(true)
459 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
460 {
461  this->CreateThreadInternal();
462 }
463 
464 inline Thread::Thread(ThreadStartDelegate&& threadStart, void* pStartParam)
465  : threadStart(std::move(threadStart))
466  , pStartParam(pStartParam)
467 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
468  , pBinaryCompatibilityExtensions(nullptr)
469 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
470  , pThreadService(nullptr)
471 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
472  , state(ThreadState::Stopped)
473  , interrupting(false)
474 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
475 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
476  , eventWakeupPtr(nullptr)
477  , semIsStartable(0)
478  , semStart(0)
479  , semIsStarted(0)
480  , isActive(true)
481 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
482 {
483  this->CreateThreadInternal();
484 }
485 
486 inline Thread::Thread(ThreadStartFunction threadStart, void* pStartParam)
487  : threadStart(make_delegate(threadStart))
488  , pStartParam(pStartParam)
489 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
490  , pBinaryCompatibilityExtensions(nullptr)
491 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
492  , pThreadService(nullptr)
493 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
494  , state(ThreadState::Stopped)
495  , interrupting(false)
496 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
497 #else // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
498  , eventWakeupPtr(nullptr)
499  , semIsStartable(0)
500  , semStart(0)
501  , semIsStarted(0)
502  , isActive(true)
503 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
504 {
505  this->CreateThreadInternal();
506 }
507 
508 template<class TInstance, class TFunction>
509 inline Thread::Thread(const ThreadSettings& settings, TInstance& instance, TFunction fn, void* pStartParam)
510  : Thread(settings, &instance, fn, pStartParam)
511 {
512 }
513 
514 template<class TInstance, class TFunction>
515 inline Thread::Thread(const ThreadSettings& settings, const TInstance& instance, TFunction fn, void* pStartParam)
516  : Thread(settings, &instance, fn, pStartParam)
517 {
518 }
519 
520 template<class TInstance, class TFunction>
521 inline Thread::Thread(const ThreadSettings& settings, TInstance* pInstance, TFunction fn, void* pStartParam)
522  : threadStart(make_delegate(pInstance, fn))
523  , pStartParam(pStartParam)
524 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
525  , pThreadService(nullptr)
526 #else // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
527  , pBinaryCompatibilityExtensions(nullptr)
528 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
529  , state(ThreadState::Stopped)
530  , interrupting(false)
531 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
532  , eventWakeupPtr(nullptr)
533  , semIsCreatedPtr(nullptr)
534  , semStartPtr(nullptr)
535  , semIsStartedPtr(nullptr)
536 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
537 {
538  this->CreateThreadInternal(settings);
539 }
540 
541 template<class TInstance, class TFunction>
542 inline Thread::Thread(const ThreadSettings& settings, const TInstance* pInstance, TFunction fn, void* pStartParam)
543  : threadStart(make_delegate(pInstance, fn))
544  , pStartParam(pStartParam)
545 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
546  , pThreadService(nullptr)
547 #else // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
548  , pBinaryCompatibilityExtensions(nullptr)
549 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
550  , state(ThreadState::Stopped)
551  , interrupting(false)
552 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
553  , eventWakeupPtr(nullptr)
554  , semIsCreatedPtr(nullptr)
555  , semStartPtr(nullptr)
556  , semIsStartedPtr(nullptr)
557 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
558 {
559  this->CreateThreadInternal(settings);
560 }
561 
562 inline Thread::Thread(ThreadSettings& settings, ThreadStartDelegate&& threadStart, void* pStartParam)
563  : Thread((const ThreadSettings&)settings, std::move(threadStart), pStartParam)
564 {
565 }
566 
567 inline Thread::Thread(ThreadSettings& settings, ThreadStartFunction threadStart, void* pStartParam)
568  : Thread((const ThreadSettings&)settings, threadStart, pStartParam)
569 {
570 }
571 
572 inline Thread::Thread(const ThreadSettings& settings, ThreadStartDelegate&& threadStart, void* pStartParam)
573  : threadStart(std::move(threadStart))
574  , pStartParam(pStartParam)
575 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
576  , pThreadService(nullptr)
577 #else // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
578  , pBinaryCompatibilityExtensions(nullptr)
579 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
580  , state(ThreadState::Stopped)
581  , interrupting(false)
582 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
583  , eventWakeupPtr(nullptr)
584  , semIsCreatedPtr(nullptr)
585  , semStartPtr(nullptr)
586  , semIsStartedPtr(nullptr)
587 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
588 {
589  this->CreateThreadInternal(settings);
590 }
591 
592 inline Thread::Thread(const ThreadSettings& settings, ThreadStartFunction threadStart, void* pStartParam)
593  : threadStart(make_delegate(threadStart))
594  , pStartParam(pStartParam)
595 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
596  , pThreadService(nullptr)
597 #else // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
598  , pBinaryCompatibilityExtensions(nullptr)
599 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
600  , state(ThreadState::Stopped)
601  , interrupting(false)
602 #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
603  , eventWakeupPtr(nullptr)
604  , semIsCreatedPtr(nullptr)
605  , semStartPtr(nullptr)
606  , semIsStartedPtr(nullptr)
607 #endif // #ifdef THREAD_DONT_PROVIDE_BINARY_COMPATIBILITY
608 {
609  this->CreateThreadInternal(settings);
610 }
611 
612 inline bool Thread::IsRunning(void)const
613 {
614  return (this->GetState() == ThreadState::Running);
615 }
616 
618 {
619  return Thread::pCurrentThread;
620 }
621 
622 #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
623 inline void Thread::Interrupt(void)
624 {
625  this->interrupting = true;
626 }
627 #endif // #ifdef ARP_SYSTEM_COMMONS_THREADING_THREAD_BINARY_COMPAT_MODE
628 
629 inline ThreadState Thread::GetState(void) const
630 {
631  return this->state.load();
632 }
633 
634 }}}} // end of namespace Arp::System::Commons::Threading
Event object to signal a single thread that an event has occurred. Can be used to synchronize threads...
Definition: AutoResetEvent.hpp:22
delegate< R(A...)> make_delegate(R(*const function_ptr)(A...)) noexcept
Creates a delegate from a static function.
Definition: delegate.hxx:215
static Thread * GetCurrentThread(void)
Returns the current thread of the calling context.
Definition: Thread.hpp:617
Namespace of the C++ standard library
static const std::size_t CpuAffinityAll
Use this constant to express an affinity of the thread to all available CPUs aka. cores...
Definition: Thread.hpp:104
The Thread-class provides methods to execute functions and methods in a separate thread.
Definition: Thread.hpp:91
delegate< void(void *)> ThreadStartDelegate
Definition of signature of class method to be executed in a separate thread.
Definition: Thread.hpp:101
Implementation of named or unnamed semaphore used to synchronize processes and threads.
Definition: Semaphore.hpp:22
summary>Thread is either waiting for an event, currently sleeping or waits for another thread to fini...
bool IsRunning(void) const
Determines if this thread is in running state.
Definition: Thread.hpp:612
Container class for adaptable thread settings.
Definition: ThreadSettings.hpp:12
Root namespace for the PLCnext API
ThreadState
Possible thread states.
Definition: ThreadState.hpp:14
void Interrupt(void)
Interrupts the currents execution.
Definition: Thread.hpp:623
void(* ThreadStartFunction)(void *)
Definition of signature of function to be executed in a separate thread.
Definition: Thread.hpp:98
System components used by the System, Device, Plc or Io domains.
Thread(TInstance &instance, TFunction fn, void *pStartParam=nullptr)
Constructs a Thread instance for a class method.
Definition: Thread.hpp:407
ThreadState GetState() const
Returns the current state of the thread.
Definition: Thread.hpp:629