gici-open学习日记(2):Streaming线程

gici-open——Streaming线程

  • 调用
  • `run()`函数
    • 输入处理 `processInput()`
    • 输出处理`processOutput()`
    • 输出处理`processLogging()`
  • **TODO**

调用

在主函数初始化NodeHandle对象的时候,在构造函数里,会有Streaming对象的初始化

auto streaming = std::make_shared<Streaming>(nodes, i);

然后,会在构造函数的最后,调用Streaming的成员函数来开启线程

streamings_[i]->start();
// start()成员函数
// Start thread
void Streaming::start()
{
  if (!valid_) return;

  // Create thread
  quit_thread_ = false;
  thread_.reset(new std::thread(&Streaming::run, this));
}

run()函数

run函数一上来先开启了自选等待,停止的条件必须是quit_thread_值为true(要主动调用Streaming::stop()才会把值设为true)或者SpinControl::ok()返回值要是false(主动调用kill函数)。

while (!quit_thread_ && SpinControl::ok()) {
    // 这里是判断为true才会进来,所以停止的条件就是相反的情况
  }

之后就是分别利用在构造函数中初始化的type获得的标志符,针对输入、记录以及输出三种情况做不同的处理

    if (has_input_) {
      processInput();
    }
    if (has_logging_) {
      mutex_logging_.lock();
      processLogging();
      mutex_logging_.unlock();
    }
    if (has_output_) {
      mutex_output_.lock();
      processOutput();
      mutex_output_.unlock();
    }

输入处理 processInput()

函数先调用了StreamerBase类的成员函数read()来读取

buf_size_input_ = streamer_->read(buf_input_, max_buf_size_);

read函数呢,又是直接调用了直接调用了RTKLIB中的strread函数来读取各种传输机制下的文件的

  virtual int read(uint8_t *buf, int max_size) {
    if (disable_) return 0;
    return strread(&stream_, buf, max_size);
  }

返回得到的就是读取到的数据的长度,针对不同的类型调用不同的readxxxx函数

    switch (stream->type) {
        case STR_SERIAL  : nr=readserial((serial_t *)stream->port,buff,n,msg); break;
        case STR_FILE    : nr=readfile  ((file_t   *)stream->port,buff,n,msg); break;
        case STR_TCPSVR  : nr=readtcpsvr((tcpsvr_t *)stream->port,buff,n,msg); break;
        case STR_TCPCLI  : nr=readtcpcli((tcpcli_t *)stream->port,buff,n,msg); break;
        case STR_NTRIPSVR:
        case STR_NTRIPCLI: nr=readntrip ((ntrip_t  *)stream->port,buff,n,msg); break;
        case STR_NTRIPCAS: nr=readntripc((ntripc_t *)stream->port,buff,n,msg); break;
        case STR_UDPSVR  : nr=readudpsvr((udp_t    *)stream->port,buff,n,msg); break;
        case STR_MEMBUF  : nr=readmembuf((membuf_t *)stream->port,buff,n,msg); break;
        case STR_FTP     : nr=readftp   ((ftp_t    *)stream->port,buff,n,msg); break;
        case STR_HTTP    : nr=readftp   ((ftp_t    *)stream->port,buff,n,msg); break;
        default:
            strunlock(stream);  // 解锁
            return 0;
    }

剩下的就是获取一些传输速率之类的信息

读取了数据之后,要对数据进行解码。就像作者开源的数据集里,数据都是以.bin结尾的,也就是二进制文件;而其他的传输机制也是编码后的格式,而不是直接就可以读取到。所以为了之后的处理,需要对文件数据进行解码操作。

对成员变量formators_进行遍历,这个变量也是在Streaming类的构造函数里面初始化的;然后定义对应索引的data_clusters_[i]的引用dataset,之后当前format解码得到的数据就会存放在这里。
然后就调用decode函数

int nobs = formator->decode(buf_input_, buf_size_input_, dataset);

这里的decode函数是在FormatBase基类中声明的虚函数

virtual int decode(const uint8_t *buf, int size,  std::vector<std::shared_ptr<DataCluster>>& data) = 0;

针对不同的format类型,有着不同的解码函数
gici-open学习日记(2):Streaming线程_第1张图片
这里涉及到的就是各种类型具体的解码了,(TODO)之后有时间的话可以看一下,解码之后的数据就会放在dataset里,返回得到的nobs应该就是观测值(数据)的个数
接下来的部分感觉是涉及到数据之间的联系(TODO),没完全看懂,看看后面结合到了具体的处理流程后能不能想明白一些

// Streaming.h
  DataClusters data_clusters_;  // store data from each formators
  std::vector<DataCallback> data_callbacks_;  // call external function to send data out
  using PipelinesDirect = std::map<std::string, PipelineDirect>;
  PipelinesDirect pipelines_direct_; // sending data directly to logging streams
  // outer string: send from whom, inner string: who encode the data
  using PipelinesConvert = std::map<std::string, std::map<std::string, PipelineConvert>>;
  PipelinesConvert pipelines_convert_; // sending decoded data to logging streams

// Streaming.cpp
    for (int iobs = 0; iobs < nobs; iobs++) {
      
      // Call data callback
      if (data_callbacks_.size() > 0) 
        for (auto it : data_callbacks_) {
        auto& data_callback = it;                         // 用了std::function,相当于把tag和数据包装起来了
        data_callback(formators_[i].tag, dataset[iobs]);  // 这里是为了后边可以直接调用对应的数据
      }

      // Call logger pipeline
      auto it_i = pipelines_convert_.find(formators_[i].tag);
      if (it_i == pipelines_convert_.end()) continue;
      if (it_i->second.size() == 0) continue;
      auto& pipelines = it_i->second;
      for (auto it_j : pipelines) {
        auto& pipeline = it_j.second;
        pipeline(formators_[i].tag, dataset[iobs]);       // 数据的编码格式
      }

  /// ...循环外...
  // Call direct pipeline
  for (auto it : pipelines_direct_) {       // 数据和logging直接联系起来
    auto& pipeline = it.second;
    pipeline(buf_input_, buf_size_input_);
  }

输出处理processOutput()

输出的处理和输入的处理差不多,也是先调用了StreamerBase类的成员函数write()来写入

streamer_->write(buf_output_, buf_size_output_);

write函数的内部也是调用RTKLIB中的strwrite函数,针对不同的格式有不同的函数,这里就不再具体描述了。

输出处理processLogging()

这个函数和processOutput()是完全一样的,只不过一个是用来logging的一个是用来output

TODO

这里只是简单看了一下Streaming线程run()函数干了什么,但是对于数据在程序内部运行过程中的传输还没有细看。根据manual 2.3节来看,程序里应该是会涉及到数据的传输、转换等等操作,后续在具体的代码中关注一下。

你可能感兴趣的:(gici-open,学习,c++,计算机视觉)