SDLThread::clear_msg

clear_msg用于清除等待队列中phandler是@phandler、id是@id的消息。如果@id是MQID_ANY(0xffffffff),那只比较phandler,忽略id,即清除所有目的地是@phandler的消息。

SDLThread::clear_msg(MessageHandler* phandler, uint32_t id = MQID_ANY)

为什么要存在clear_msg?——发送方调用Post(RTC_FROM_HERE, ...)把消息放到队列(msgq_或dmsgq_),接收方调用MessageQueue::Get从队列出取出并处理消息,这里有一个时差。如果在这个期间,发生了接收方被销毁,既然接收方没了,必须把还留在队列中消息删除掉。

在实现上,clear_msg是通过调用webrtc中的rtc::Thread::Clear。

namespace rtc {
class SDLThread : public Thread
{
public:
	...
	void pump()
	{
		Message msg;
		size_t max_msgs = std::max<size_t>(1, size());
		// require detect io signal, so io_process of Get use true.
		for (; max_msgs > 0 && Get(&msg, 0, true); --max_msgs) {

“Get(...)”见下文的“MessageQueue::Get”。Get后,消息就从队列中取出,离开队列。Dispatch功能是把消息分发到对应从rtc::MessageHandler派生的接者者,并调用它的“OnMessage(rtc::Message* msg)”方法。

			Dispatch(&msg);
		}
	}
	void clear_msg(MessageHandler* phandler, uint32_t id = MQID_ANY)
	{
		Clear(phandler, id);
	}
};

}

为理解怎么工作,让观察一次sdl_thread_.clear_msg(...)如何清除还处在队列中消息。由于Post()和Get()间隔很短,为能捕捉到,需修改源码。为方便测试,建议用tbase_camera框架。举个例子,弹出一个执行tbase_camera任务的窗口,像dnn中的识别物体,然后再关闭。

 

步骤1:在从rtc::MessageData派生类型的析构函数设断点

要测试Post的消息,假设message_id值是4(POST_MSG_SWITCH_CAMERA),消息对应、从rtc::MessageData派生的类型是tmsg_data_base_camera,并在该析构函数~tmsg_data_base_camera内设断点。

 

步骤2:修改MessageQueue::Get。让遇到message_id是4的消息时,不发送,继续放在队列里

<webrtc>/rtc_base/messagequeue.cc
------
bool MessageQueue::Get(Message *pmsg, int cmsWait, bool process_io) {
        ......
        // Pull a message off the message queue, if available.
        if (msgq_.empty()) {
          break;
        } else if (msgq_.front().message_id == 4) { 
            break;

这个“else if”是为调试加的。假定你要让值是4的message_id不被发送,一直放在队列中。当然,这也会导致后绪message都不被接收。

        } else {
          *pmsg = msgq_.front();
          msgq_.pop_front();
        }
      }  // crit_ is released here.
  ......
}

要分发的消息放在msgq_或dmsgq_。不清楚它们之间不同,只是测试下来,rtc::Thread::Current()->Post(RTC_FROM_HERE, ...)发出的消息放在msgq_。这里修改让值是4的message_id不被发送,一直放在队列中。

 

步骤3:确定接收端OnMessage没收到message_id

对tbase_camera,那就是不被调用tmessage_handler::OnMessage。

 

步骤4:关闭窗口,确定该tmsg_data_base_camera的析构函数被调用。然后查看“Call Stack”,确认是在sdl_thread_.clear_msg(...)中

<librose>/gui/dialogs/dialog.cpp
------
bool tdialog::show(const unsigned explicit_x, const unsigned explicit_y)
{
  ......
  instance->sdl_thread().clear_msg(this);
  instance->sdl_thread().clear_msg(&instance->msg_handler());
  ......
}

关闭窗口,会调用两个接收者clear_msg,一个是窗口自身,一个是tbase_instance中的msg_hander_。后者用于不方便依赖于某个窗口的,像tbase_camera。

图1 clear_msg

在图1,msgq_中有一个消息,变量it显示了该消息内容。它的message_id是4,phandler是0x04b3399c。it->Match作用是判断消息是否匹配,由于参数id是MQID_ANY(0xffffffff),即忽略id,那只要phandler一样就行。参数removed是个消息列表,一旦不为空的话,匹配的消息不是删除,而是放到这个列表中。

执行“delete it->pdata”将删除这条消息,这确认了clear_msg能删除功能。 

全部评论: 0

    写评论: