运行时类型信息(RTTI) C++中通过<typeinfo>
和 <typeindex>
头文件提供了运行时类型信息(RTTI)的支持,主要用于类型识别和类型比较。
1. <typeinfo>
提供运行时类型信息(RTTI),主要包含:
typeid
运算符:获取类型的 type_info
对象
type_info
类:包含类型信息
示例一:基本类型检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 int i = 42 ; double d = 3.14 ; std::cout << "i is of type: " << typeid (i).name () << '\n' ; std::cout << "d is of type: " << typeid (d).name () << '\n' ; if (typeid (i) == typeid (int )) { std::cout << "i is definitely an int\n" ; } if (typeid (d) == typeid (double )) { std::cout << "d is definitely a double\n" ; }
示例二:多态类型检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Base { public : virtual ~Base () { } }; class Derived : public Base{ }; int main () { Base* b = new Derived (); std::cout << "Actual type of b is: " << typeid (*b).name () << std::endl; delete b; return 0 ; }
2.<typeindex>
提供std::type_index
的类,是type_info
的包装类,可以用作关联容器的键
示例三:在map中使用类型索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <typeinfo> #include <typeindex> #include <unordered_map> #include <string> int main () { std::unordered_map<std::type_index, std::string> type_names; type_names[std::type_index (typeid (int ))] = "int" ; type_names[std::type_index (typeid (double ))] = "double" ; type_names[std::type_index (typeid (std::string))] = "string" ; int x; double y; std::string z; std::cout << "x is a " << type_names[std::type_index (typeid (x))] << '\n' ; std::cout << "y is a " << type_names[std::type_index (typeid (y))] << '\n' ; std::cout << "z is a " << type_names[std::type_index (typeid (z))] << '\n' ; }
Actor设计模式 actor通过消息传递的方式与外界通信。消息传递是异步的。每个actor都有一个邮箱,该邮箱接收并缓存其他actor发过来的消息,actor一次只能同步处理一个消息,处理消息过程中,除了可以接收消息,不能做任何其他操作。 每一个类独立在一个线程里称作Actor,Actor之间通过队列通信,比如Actor1 发消息给Actor2, Actor2 发消息给Actor1都是投递到对方的队列中。好像给对方发邮件,对方从邮箱中取出一样。如下图
Actor模型的另一个好处就是可以消除共享状态,因为它每次只能处理一条消息,所以actor内部可以安全的处理状态,而不用考虑锁机制。
Actor在C++中的简单实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 #ifndef ACTOR_H #define ACTOR_H #include <chrono> #include <condition_variable> #include <exception> #include <functional> #include <iostream> #include <memory> #include <mutex> #include <queue> #include <stdexcept> #include <string> #include <thread> #include <typeinfo> #include <unordered_map> #include <utility> #include <atomic> namespace actor{ class Message { public : virtual ~Message () { } virtual std::string type () const = 0 ; virtual std::string toString () const { return type (); } }; template <typename Derived>class TypedMessage : public Message{ public : std::string type () const override { return typeid (Derived).name (); } }; struct TextMessage : public TypedMessage<TextMessage>{ std::string content; explicit TextMessage (std::string c) : content(std::move(c)) { } std::string toString () const override { return "TextMessage: " + content; } }; struct StopMessage : public TypedMessage<StopMessage>{ std::string toString () const override { return "StopMessage" ; } }; struct TimeoutMessage : public TypedMessage<TimeoutMessage>{ std::string toString () const override { return "TimeoutMessage" ; } }; using MessagePtr = std::shared_ptr<Message>;class Actor : public std::enable_shared_from_this<Actor>{ friend class ActorSystem ; public : Actor () : running_ (true ) { } virtual ~Actor () { if (thread_.joinable ()) thread_.join (); } void start () { thread_ = std::thread (&Actor::run, this ); std::cout << "[" << name_ << "] started." << std::endl; } template <typename T, typename ... Args> void send (Args&&... args) { auto msg = std::make_shared <T>(std::forward<Args>(args)...); { std::lock_guard<std::mutex> lock (mutex_) ; mailbox_.push (msg); } cv_.notify_all (); } void send (MessagePtr msg) { { std::lock_guard<std::mutex> lock (mutex_) ; mailbox_.push (msg); } cv_.notify_all (); } template <typename T, typename ... Args> void sendAfter (std::chrono::milliseconds delay, Args&&... args) { std::weak_ptr<Actor> weakSelf = shared_from_this (); std::thread ( [weakSelf, delay, args...]() { std::this_thread::sleep_for (delay); if (auto self = weakSelf.lock ()) { self->send <T>(args...); } }) .detach (); } void setName (const std::string& name) { name_ = name; } std::string getName () const { return name_; } void setProcessTimeout (std::chrono::milliseconds timeout) { process_timeout_ = timeout; } void join () { if (thread_.joinable ()) thread_.join (); } protected : virtual void onMessage (MessagePtr msg) = 0 ; virtual void onTimeout () { send <TimeoutMessage>(); } virtual void onStop () { } virtual void onStart () { } private : void run () { onStart (); while (running_) { MessagePtr msg; { std::unique_lock<std::mutex> lock (mutex_) ; if (cv_.wait_for (lock, process_timeout_, [&]() { return !mailbox_.empty (); })) { msg = mailbox_.front (); mailbox_.pop (); } else { onTimeout (); continue ; } } std::cout << "[" << name_ << "] received message: " << msg->toString () << std::endl; if (std::dynamic_pointer_cast <StopMessage>(msg)) { std::cout << "[" << name_ << "] stopping by StopMessage." << std::endl; running_ = false ; break ; } try { onMessage (std::move (msg)); } catch (const std::exception& e) { std::cerr << "Exception in " << name_ << ": " << e.what () << std::endl; } } onStop (); std::cout << "[" << name_ << "] stopped." << std::endl; } void stop () { if (running_) { send <StopMessage>(); running_ = false ; } } private : std::atomic<bool > running_; std::thread thread_; std::queue<MessagePtr> mailbox_; std::mutex mutex_; std::condition_variable cv_; std::string name_; std::chrono::milliseconds process_timeout_{1000 }; }; class ActorSystem { public : ~ActorSystem () { shutdown (); } template <typename T, typename ... Args> std::shared_ptr<T> createActor (const std::string& name, Args&&... args) { auto actor = std::make_shared <T>(std::forward<Args>(args)...); registerActor (name, actor); actor->start (); return actor; } void registerActor (const std::string& name, std::shared_ptr<Actor> actor) { std::lock_guard<std::mutex> lock (mutex_) ; if (actors_.count (name)) throw std::runtime_error ("Actor already exists: " + name); actor->setName (name); actors_[name] = actor; } std::shared_ptr<Actor> getActor (const std::string& name) { std::lock_guard<std::mutex> lock (mutex_) ; auto it = actors_.find (name); return (it != actors_.end ()) ? it->second : nullptr ; } void broadcast (MessagePtr msg) { std::lock_guard<std::mutex> lock (mutex_) ; for (auto & [_, actor] : actors_) actor->send (msg); } void shutdown () { std::cout << "begin shutdown" << std::endl; { std::lock_guard<std::mutex> lock (mutex_) ; for (auto & [_, actor] : actors_) actor->send <StopMessage>(); } { std::lock_guard<std::mutex> lock (mutex_) ; for (auto & [_, actor] : actors_) actor->join (); actors_.clear (); } std::cout << "shutdown finished" << std::endl; } private : std::unordered_map<std::string, std::shared_ptr<Actor>> actors_; std::mutex mutex_; }; } #endif
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include "actor_system.h" #include <iostream> using namespace actor;class Printer : public Actor{ protected : void onMessage (MessagePtr msg) override { if (auto text = std::dynamic_pointer_cast <TextMessage>(msg)) { std::cout << "[printer] " << text->content << std::endl; } } }; class Pinger : public Actor{ public : Pinger (ActorSystem& system) : system_ (system) { } protected : void onStart () override { send <TextMessage>("Ping" ); } void onMessage (MessagePtr msg) override { if (auto text = std::dynamic_pointer_cast <TextMessage>(msg)) { std::cout << "[pinger] received: " << text->content << std::endl; if (text->content == "Ping" ) { auto printer = system_.getActor ("printer" ); if (printer) { printer->send <TextMessage>("Ping!" ); } } } } private : ActorSystem& system_; }; int main () { ActorSystem system; auto printer = system.createActor <Printer>("printer" ); auto pinger = system.createActor <Pinger>("pinger" , std::ref (system)); std::this_thread::sleep_for (std::chrono::seconds (1 )); system.shutdown (); return 0 ; }