栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

apollo源码解读:信号槽机制

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

apollo源码解读:信号槽机制

大家都知道Qt的信号槽机制给编程带来了极大的便利,阿波罗通讯主要通过同一channel的读写,简而言之就是发布订阅模型,这个时候信号槽的机制就显得极为实用,阿波罗在cyber基础类库里面用C++模板类自己写了一套信号槽机制,值的学习。


#ifndef CYBER_BASE_SIGNAL_H_
#define CYBER_BASE_SIGNAL_H_

#include 
#include 
#include 
#include 
#include 

namespace apollo {
namespace cyber {
namespace base {

template 
class Slot;

template 
class Connection;

template 
class Signal {
 public:
  using Callback = std::function;
  using SlotPtr = std::shared_ptr;
  using SlotList = std::list;
  using ConnectionType = Connection;

  Signal() {}
  virtual ~Signal() { DisconnectAllSlots(); }

  void operator()(Args... args) {
    SlotList local;
    {
      std::lock_guard lock(mutex_);
      for (auto& slot : slots_) {
        local.emplace_back(slot);
      }
    }

    if (!local.empty()) {
      for (auto& slot : local) {
        (*slot)(args...);
      }
    }

    ClearDisconnectedSlots();
  }

  ConnectionType Connect(const Callback& cb) {
    auto slot = std::make_shared(cb);
    {
      std::lock_guard lock(mutex_);
      slots_.emplace_back(slot);
    }

    return ConnectionType(slot, this);
  }

  bool Disconnect(const ConnectionType& conn) {
    bool find = false;
    {
      std::lock_guard lock(mutex_);
      for (auto& slot : slots_) {
        if (conn.HasSlot(slot)) {
          find = true;
          slot->Disconnect();
        }
      }
    }

    if (find) {
      ClearDisconnectedSlots();
    }
    return find;
  }

  void DisconnectAllSlots() {
    std::lock_guard lock(mutex_);
    for (auto& slot : slots_) {
      slot->Disconnect();
    }
    slots_.clear();
  }

 private:
  Signal(const Signal&) = delete;
  Signal& operator=(const Signal&) = delete;

  void ClearDisconnectedSlots() {
    std::lock_guard lock(mutex_);
    slots_.erase(
        std::remove_if(slots_.begin(), slots_.end(),
                       [](const SlotPtr& slot) { return !slot->connected(); }),
        slots_.end());
  }

  SlotList slots_;
  std::mutex mutex_;
};

template 
class Connection {
 public:
  using SlotPtr = std::shared_ptr;
  using SignalPtr = Signal*;

  Connection() : slot_(nullptr), signal_(nullptr) {}
  Connection(const SlotPtr& slot, const SignalPtr& signal)
      : slot_(slot), signal_(signal) {}
  virtual ~Connection() {
    slot_ = nullptr;
    signal_ = nullptr;
  }

  Connection& operator=(const Connection& another) {
    if (this != &another) {
      this->slot_ = another.slot_;
      this->signal_ = another.signal_;
    }
    return *this;
  }

  bool HasSlot(const SlotPtr& slot) const {
    if (slot != nullptr && slot_ != nullptr) {
      return slot_.get() == slot.get();
    }
    return false;
  }

  bool IsConnected() const {
    if (slot_) {
      return slot_->connected();
    }
    return false;
  }

  bool Disconnect() {
    if (signal_ && slot_) {
      return signal_->Disconnect(*this);
    }
    return false;
  }

 private:
  SlotPtr slot_;
  SignalPtr signal_;
};

template 
class Slot {
 public:
  using Callback = std::function;
  Slot(const Slot& another)
      : cb_(another.cb_), connected_(another.connected_) {}
  explicit Slot(const Callback& cb, bool connected = true)
      : cb_(cb), connected_(connected) {}
  virtual ~Slot() {}

  void operator()(Args... args) {
    if (connected_ && cb_) {
      cb_(args...);
    }
  }

  void Disconnect() { connected_ = false; }
  bool connected() const { return connected_; }

 private:
  Callback cb_;
  bool connected_ = true;
};

}  // namespace base
}  // namespace cyber
}  // namespace apollo

#endif  // CYBER_BASE_SIGNAL_H_

1.和qt的信号槽差不多,不处理返回值,即发送信号函数没有返回值,槽函数执行不处理返回值

2.信号、槽、连接都封装成了类

3.推荐信号和槽参数一致

4.主要用到地方:底层通信机制

来看看怎么使用

#include 
#include "cyber/cyber.h"
using namespace apollo::cyber::base;
int main(int argc, char* argv[]) {
  { //使用中可能不需要使用Connection类
    int sum_a = 0;
    Signal sig;
    Slot slot([&sum_a](int a, int b) { sum_a = a + b; });
    sig.Connect(slot);
    sig(100, 1);
    std::cout << sum_a << std::endl;
  }

  { //甚至可以不使用Slot类,Connect函数将匿名函数隐式转换了
    int sum_a = 0;
    Signal sig;
    sig.Connect([&sum_a](int a, int b) { sum_a = a + b; });
    sig(100, 1);
    std::cout << sum_a << std::endl;
  }
  return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1008742.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号