当两个对象都在各自的线程中运行时,您可以使用channels(或管道、或队列,或者您想调用它们的任何方式)在这两个对象之间进行通信。
您为每个对象创建一个通道,并将对它们的引用作为发送端和接收端分别传递给对象。对象可以在其接收端作为参与者侦听消息,并在接收和接收新消息时对它们采取行动。这打破了循环依赖,因为每个对象现在都持有对它们相互通信的通道的引用。
频道:
// The interface for the sending end of a Channel
template<typename T>
class SendingChannel {
public:
virtual void send(T) = 0;
virtual ~SendingChannel() = default;
};
// The interface for the receiving end of a Channel
template<typename T>
class ReceivingChannel {
public:
virtual T receive() = 0;
virtual ~ReceivingChannel() = default;
};
// The implementation for a whole Channel
template<typename T>
class Channel: public SendingChannel<T>, public ReceivingChannel<T> {
private:
std::queue<T> msgs{};
std::mutex channel_mtx{};
std::condition_variable receiving_finishable{};
public:
bool is_empty() const { return msgs.empty(); }
bool is_not_empty() const { return !is_empty(); }
void send(T msg) override {
std::lock_guard channel_lck{channel_mtx};
msgs.push(std::move(msg));
receiving_finishable.notify_one();
}
T receive() override {
std::unique_lock channel_lck{channel_mtx};
receiving_finishable.wait(
channel_lck,
[this](){ return is_not_empty(); }
);
T msg{std::move(msgs.front())};
msgs.pop();
return msg;
}
};
用于对象之间通信的消息可能由表示类型的枚举组成,也可能由表示传输不同类型值的能力的variant 组成。但不同的值和动作类型也可以通过多态消息类型或functial standard library 的function 来传达。
演员的执行循环:
while (true) {
auto message = inbox.receive();
switch (message.type) {
case MsgType::PrintHello:
print_hello();
break;
case MsgType::PrintMessage:
print_message(get<std::string>(message.argument));
break;
case MsgType::GetValue:
send_value();
break;
case MsgType::Value:
print_value(get<int>(message.argument));
break;
}
}
主要:
int main() {
Channel<Message> to_b;
Channel<Message> to_a;
Object a("A", to_a, to_b);
Object b("B", to_b, to_a);
thread thread_a{a};
thread thread_b{b};
to_a.send(Message{MsgType::PrintMessage, "Hello, World!"});
to_b.send(Message{MsgType::PrintHello});
thread_a.join();
thread_b.join();
}
正如您在main 中看到的,不需要任何指针,不需要在堆上声明任何内容,也没有循环引用。通道是隔离线程和在其上运行的对象的一个不错的解决方案。 Actor 可以通过线程安全的通道进行操作和通信。
我的完整示例可以在 my Github repo 上查看。