webrtc源码学习 - 3种异步处理

文章目录

  • 1、webrtc 3中异步调用方式
  • 2、具体实现
    • 2.1 TaskQueue
    • 2.2 AsyncInvoker
    • 2.3 SynchronousMethodCall

1、webrtc 3中异步调用方式

在webrtc 任务中有3种不同的异步处理方式,用于解决不同的问题,如下
1)taskqueue 每个队列上有一个线程执行,线程不需要指定
2)asyncTask 在指定的线程上执行,需要指定线程
3)SynchronousMethodCall 在指定线程执行完成后,同步等待结果(跨线程同步调用)

2、具体实现

2.1 TaskQueue

webrtc源码学习 - 3种异步处理_第1张图片

TaskQueue :是TaskQueueBase 的代理封装,是依赖注入的方法实现。
TaskQueueBase : 抽象接口
TaskQueueWin:
1、创建一个线程,并启动,每个任务队列有一个线程
2、在线程不断的读取task, 并执行
3、可以支持延迟任务

// 创建线程
TaskQueueWin::TaskQueueWin(absl::string_view queue_name,
                           rtc::ThreadPriority priority)
    : thread_(&TaskQueueWin::ThreadMain, this, queue_name, priority),
      in_queue_(::CreateEvent(nullptr, true, false, nullptr)) {
  RTC_DCHECK(in_queue_);
  thread_.Start();
  
  //启动线程
  rtc::Event event(false, false);
  RTC_CHECK(thread_.QueueAPC(&InitializeQueueThread,
                             reinterpret_cast<ULONG_PTR>(&event)));
  //等待线程初始化完成                           
  event.Wait(rtc::Event::kForever);
}
  
  //线程主循环
void TaskQueueWin::RunThreadMain() {
  CurrentTaskQueueSetter set_current(this);
  HANDLE handles[2] = {*timer_.event_for_wait(), in_queue_};
  while (true) {
    // Make sure we do an alertable wait as that's required to allow APCs to run
    // (e.g. required for InitializeQueueThread and stopping the thread in
    // PlatformThread).
    DWORD result = ::MsgWaitForMultipleObjectsEx(
        arraysize(handles), handles, INFINITE, QS_ALLEVENTS, MWMO_ALERTABLE);
    RTC_CHECK_NE(WAIT_FAILED, result);
    if (result == (WAIT_OBJECT_0 + 2)) {
      // There are messages in the message queue that need to be handled.
      // PeekMessage 
      if (!ProcessQueuedMessages())
        break;
    }

    if (result == WAIT_OBJECT_0 ||
        (!timer_tasks_.empty() &&
         ::WaitForSingleObject(*timer_.event_for_wait(), 0) == WAIT_OBJECT_0)) {
      // The multimedia timer was signaled.
      timer_.Cancel();
      RunDueTasks();//延迟
      ScheduleNextTimer();
    }
    //
    if (result == (WAIT_OBJECT_0 + 1)) {
      ::ResetEvent(in_queue_);
      RunPendingTasks(); //异步任务
    }
  }
}

2.2 AsyncInvoker

异步调用,实现就是调用了thread->Post 方法

1、使用的时候可以在指定线程运行

if (!network_thread_) {
    owned_network_thread_ = rtc::Thread::CreateWithSocketServer();
    owned_network_thread_->SetName("pc_network_thread", nullptr);
    owned_network_thread_->Start();
    network_thread_ = owned_network_thread_.get();
  }
  // 异步调用,在network_thread_ 上执行
invoker_.AsyncInvoke<void>(RTC_FROM_HERE, network_thread_, [this, channel_id, frame] {
    other_->OnData(channel_id, frame);
  });

2、异步执行的实现
1、利用继承,AsyncClosure模板类进行类型擦除,保存FunctorT
2、调用 thread->Post

// 异步调用的实现
template <class ReturnT, class FunctorT>
  void AsyncInvoke(const Location& posted_from,
                   Thread* thread,
                   FunctorT&& functor,
                   uint32_t id = 0) {
                       //类型擦除,保存function
    std::unique_ptr<AsyncClosure> closure(
        new FireAndForgetAsyncClosure<FunctorT>(
            this, std::forward<FunctorT>(functor)));
    DoInvoke(posted_from, thread, std::move(closure), id);
  }

void AsyncInvoker::DoInvoke(const Location& posted_from,
                            Thread* thread,
                            std::unique_ptr<AsyncClosure> closure,
                            uint32_t id) {
  if (destroying_.load(std::memory_order_relaxed)) {
    // Note that this may be expected, if the application is AsyncInvoking
    // tasks that AsyncInvoke other tasks. But otherwise it indicates a race
    // between a thread destroying the AsyncInvoker and a thread still trying
    // to use it.
    RTC_LOG(LS_WARNING) << "Tried to invoke while destroying the invoker.";
    return;
  }
  thread->Post(posted_from, this, id,
               new ScopedMessageData<AsyncClosure>(std::move(closure)));
}

3、调用线程Post 方法(继承与MessageQueue)
1、存储msg 在队列中
2、msqqueue 利用SocketServer 做的同步


void MessageQueue::Post(const Location& posted_from,
                        MessageHandler* phandler,
                        uint32_t id,
                        MessageData* pdata,
                        bool time_sensitive) {
  if (IsQuitting()) {
    delete pdata;
    return;
  }

  // Keep thread safe
  // Add the message to the end of the queue
  // Signal for the multiplexer to return

  {
    CritScope cs(&crit_);
    Message msg;
    msg.posted_from = posted_from;
    msg.phandler = phandler;
    msg.message_id = id;
    msg.pdata = pdata;
    if (time_sensitive) {
      msg.ts_sensitive = TimeMillis() + kMaxMsgLatency;
    }
    msgq_.push_back(msg);
  }
  WakeUpSocketServer();
}
               

4、thread 的处理函数
1、thread 启动后,bool Thread::ProcessMessages(int cmsLoop)
2、获取消息队列的信息

bool Thread::ProcessMessages(int cmsLoop) {

while (true) {
#if defined(WEBRTC_MAC)
    ScopedAutoReleasePool pool;
#endif
    Message msg;
    if (!Get(&msg, cmsNext)) // 同步获取消息
      return !IsQuitting();
    Dispatch(&msg);

    if (cmsLoop != kForever) {
      cmsNext = static_cast<int>(TimeUntil(msEnd));
      if (cmsNext < 0)
        return true;
    }
  }
}  

// 分发消息
void MessageQueue::Dispatch(Message* pmsg) {
  TRACE_EVENT2("webrtc", "MessageQueue::Dispatch", "src_file_and_line",
               pmsg->posted_from.file_and_line(), "src_func",
               pmsg->posted_from.function_name());
  int64_t start_time = TimeMillis();
  pmsg->phandler->OnMessage(pmsg); //符号
  int64_t end_time = TimeMillis();
  int64_t diff = TimeDiff(end_time, start_time);
  if (diff >= kSlowDispatchLoggingThreshold) {
    RTC_LOG(LS_INFO) << "Message took " << diff
                     << "ms to dispatch. Posted from: "
                     << pmsg->posted_from.ToString();
  }
}

2.3 SynchronousMethodCall

非常简单,封装了线程,然后利用信号等待执行完成

SynchronousMethodCall::SynchronousMethodCall(rtc::MessageHandler* proxy)
    : proxy_(proxy) {}

SynchronousMethodCall::~SynchronousMethodCall() = default;

void SynchronousMethodCall::Invoke(const rtc::Location& posted_from,
                                   rtc::Thread* t) {
  if (t->IsCurrent()) {
    proxy_->OnMessage(nullptr);
  } else {
    t->Post(posted_from, this, 0);
    e_.Wait(rtc::Event::kForever); //等执行结果
  }
}

void SynchronousMethodCall::OnMessage(rtc::Message*) {
  proxy_->OnMessage(nullptr);
  e_.Set(); //执行完成,发送信号
}

提供了helper 类MethodCall*
调用示例

 MethodCall0<PeerConnectionFactory, bool> call(
      pc_factory.get(), &PeerConnectionFactory::Initialize);
  bool result = call.Marshal(RTC_FROM_HERE, pc_factory->signaling_thread());

MethodCall* 主要的功能
1、利用模板类,构造函数封装了执行函数
2、调用 SynchronousMethodCall::Invoke
3、线程执行OnMessage,执行{ r_.Invoke(c_, m_); } 结果保存在r_中
4、在执行线程执行完成后,返回结果r_.moved_result();


template <typename C, typename R>
class MethodCall0 : public rtc::Message, public rtc::MessageHandler {
 public:
  typedef R (C::*Method)();
  MethodCall0(C* c, Method m) : c_(c), m_(m) {}

  R Marshal(const rtc::Location& posted_from, rtc::Thread* t) {
    internal::SynchronousMethodCall(this).Invoke(posted_from, t);
    return r_.moved_result();
  }

 private:
  void OnMessage(rtc::Message*) { r_.Invoke(c_, m_); }

  C* c_;
  Method m_;
  ReturnType<R> r_;
};

你可能感兴趣的:(webrtc,webrtc)