rby1-sdk
Loading...
Searching...
No Matches
thread.h
1#pragma once
2
3#include <functional>
4#include <stdexcept>
5#include <string>
6#include <thread>
7#include <utility>
8
9#include "rby1-sdk/export.h"
10
11#if defined(_WIN32)
12#include <Windows.h>
13#elif defined(__APPLE__)
14#include <mach/mach.h>
15#include <mach/thread_policy.h>
16#else
17#include <pthread.h>
18#include <sched.h>
19#include <unistd.h>
20#endif
21
22#if defined(_WIN32)
23#define POLICY_DEFAULT_VALUE 0
24#else
25#define POLICY_DEFAULT_VALUE SCHED_OTHER
26#endif
27
28namespace rb {
29
30class RBY1_SDK_API Thread {
31 public:
32 using Functor = std::function<void()>;
33
34 Thread(std::string name = "", int cpuid = -1, int priority = 0, int policy = POLICY_DEFAULT_VALUE)
35 : thread_(),
36 name_(std::move(name)),
37 cpuid_(cpuid),
38 priority_(priority),
39 policy_(policy),
40 started_(false),
41 running_(false) {}
42
43 ~Thread() {
44 if (started_) {
45 if (thread_.joinable()) {
46 thread_.join();
47 }
48 }
49 }
50
51 void SetName(const std::string& name) { name_ = name; }
52
53 void SetAffinity(int cpuid) { cpuid_ = cpuid; }
54
55 void SetOSPriority(int priority, int policy) {
56 priority_ = priority;
57 policy_ = policy;
58 }
59
60 void StartFunc(const Functor& func) {
61 if (started_) {
62 throw std::runtime_error("Thread already started");
63 }
64
65 thread_ = std::thread([this, func]() {
66 running_ = true;
67
68 SetThreadName();
69 SetThreadAffinity();
70 SetThreadPriority();
71
72 func();
73
74 running_ = false;
75 });
76
77 started_ = true;
78 }
79
80 bool IsRunning() const { return running_; }
81
82 void Join() {
83 if (thread_.joinable()) {
84 thread_.join();
85 }
86 }
87
88 private:
89 std::thread thread_;
90 std::string name_;
91 int cpuid_;
92 int priority_;
93 int policy_;
94 bool started_;
95 std::atomic<bool> running_{};
96
97 void SetThreadName() {
98 if (!name_.empty()) {
99#if defined(_WIN32)
100 const DWORD MS_VC_EXCEPTION = 0x406D1388;
101
102#pragma pack(push, 8)
103
104 typedef struct tagTHREADNAME_INFO {
105 DWORD dwType; // must be 0x1000
106 LPCSTR szName; // thread name
107 DWORD dwThreadID; // thread ID (-1 = caller thread)
108 DWORD dwFlags; // reserved for future use, must be zero
109 } THREADNAME_INFO;
110
111#pragma pack(pop)
112
113 THREADNAME_INFO info;
114 info.dwType = 0x1000;
115 info.szName = name_.c_str();
116 info.dwThreadID = GetCurrentThreadId();
117 info.dwFlags = 0;
118
119 __try {
120 RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
121 } __except (EXCEPTION_EXECUTE_HANDLER) {}
122#elif defined(__APPLE__)
123 pthread_setname_np(name_.c_str());
124#else
125 pthread_setname_np(pthread_self(), name_.c_str());
126#endif
127 }
128 }
129
130 void SetThreadAffinity() { // NOLINT
131 if (cpuid_ != -1) {
132#if defined(_WIN32)
133 DWORD_PTR mask = 1 << cpuid_;
134 SetThreadAffinityMask(GetCurrentThread(), mask);
135#elif defined(__APPLE__)
136 thread_affinity_policy_data_t policy = {cpuid_};
137 thread_port_t mach_thread = pthread_mach_thread_np(pthread_self());
138 kern_return_t ret = thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY, (thread_policy_t)&policy, 1);
139 if (ret != KERN_SUCCESS) {
140 throw std::runtime_error("Error setting thread affinity on macOS");
141 }
142#else
143 cpu_set_t cpuset;
144 CPU_ZERO(&cpuset);
145 CPU_SET(cpuid_, &cpuset);
146
147 int rc = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset);
148 if (rc != 0) {
149 throw std::runtime_error("Error calling pthread_setaffinity_np");
150 }
151#endif
152 }
153 }
154
155 void SetThreadPriority() { // NOLINT
156 if (priority_ != 0) {
157#if defined(_WIN32)
158 int win_priority = THREAD_PRIORITY_NORMAL;
159 if (priority_ > 0) {
160 win_priority = THREAD_PRIORITY_HIGHEST;
161 } else if (priority_ < 0) {
162 win_priority = THREAD_PRIORITY_LOWEST;
163 }
164 ::SetThreadPriority(GetCurrentThread(), win_priority);
165#else
166 struct sched_param param{};
167
168 param.sched_priority = priority_;
169
170 int rc = pthread_setschedparam(pthread_self(), policy_, &param);
171 if (rc != 0) {
172 throw std::runtime_error("Error calling pthread_setschedparam");
173 }
174#endif
175 }
176 }
177};
178
179} // namespace rb
Definition thread.h:30