
一、消息队列的使用
1、 需在以下文件中配置如下内容
OS_CFGH
OS_MAX_QS N 你需要的值
根据需要自己配置
#define OS_Q_EN 1 / Enable (1) or Disable (0) code generation for QUEUES /
#define OS_Q_ACCEPT_EN 1 / Include code for OSQAccept() /
#define OS_Q_DEL_EN 1 / Include code for OSQDel() /
#define OS_Q_FLUSH_EN 1 / Include code for OSQFlush() /
#define OS_Q_POST_EN 1 / Include code for OSQPost() /
#define OS_Q_POST_FRONT_EN 1 / Include code for OSQPostFront() /
#define OS_Q_POST_OPT_EN 1 / Include code for OSQPostOpt() /
#define OS_Q_QUERY_EN 1 / Include code for OSQQuery() /
2、 建立一个指向消息数组的指针和数组的大小,该指针数组必须申明为void类型,如下:
void MyArrayOfMsg[SIZE];
3、 声明一个OS_EVENT类型的指针指向生成的队列,如下:
OS_EVENT QSem;
4、 调用OSQcreate()函数创建消息队列,如下:
QSem = OSQcreate(&MyArrayOfMsg[0],SIZE);
5、 等待消息队列中的消息,OSQPend()。void OSQPend (OS_EVENT pevent, INT16U timeout, INT8U err):
必须保证消息队列已经被建立。
timeout定义的是等待超时时间,如果为0则表示无期限的等待
err表示的是在等待消息队列出错时的返回类型,有以下几种:
OS_ERR_PEVENT_NULL //消息队列不存在
OS_ERR_EVENT_TYPE
OS_TIMEOUT //消息队列等待超时
OS_NO_ERR //消息队列接收到消息
获得消息队列示例
type GETQ;
INT8U err;
GETQ = (type )OSQPend(QSem, time, &err);
if(err == OS_NO_ERR){
无错处理
}
else{
出错处理
}
61 向消息队列发送一则消息(FIFO),OSQPost(); INT8U OSQPost (OS_EVENT pevent, void msg):
函数返回值有:
OS_ERR_PEVENT_NULL
OS_ERR_POST_NULL_PTR
OS_ERR_EVENT_TYPE
OS_Q_FULL
OS_NO_ERR
参数:pevent,msg
62 向消息队列发送一则消息(LIFO) INT8U OSQPostFront (OS_EVENT pevent, void msg)
63 向消息队列发送一则消息(LIFO或者FIFO) INT8U OSQPostOpt (OS_EVENT pevent, void msg, INT8U opt)
参数: opt
如果经opt参数中的OS_POST_OPT_BROADCAST位置为1,则所有正在等待消息的任务都能接收到这则消息,并且被OS_EventTaskRdy()从等待列表中删除
如果不是广播方式,则只有等待消息的任务中优先级最高的任务能够进入就绪态。然后,OS_EventTaskRdy()从等待列表中把等待消息的任务中优先级最高的任务删除。
注: 如果此函数由ISR调用,则不会发生任务切换,直到中断嵌套的最外层中断服务子程序调用OSIntExit()函数时,才能进行任务切换
7、 无等待的从消息队列中获得消息,OSQAccept(); void OSQAccept (OS_EVENT pevent, INT8U err)
err可能的返回值:
OS_ERR_PEVENT_NULL
OS_Q_EMPTY
OS_NO_ERR
函数的返回值:消息,0
8、 清空消息队列 INT8U OSQFlush (OS_EVENT pevent)
函数返回值:
OS_ERR_PEVENT_NULL
OS_ERR_EVENT_TYPE
OS_NO_ERR
9、 获取消息队列的状态,OSQQuery(); INT8U OSQQuery (OS_EVENT pevent, OS_Q_DATA p_q_data)
函数返回值:
OS_ERR_PEVENT_NULL
OS_ERR_EVENT_TYPE
OS_NO_ERR
OS_Q_DATA数据结构在ucos_iih中
一、问题:在Android启动后会在新进程里创建一个主线程,也叫UI线程( 非线程安全 )这个线程主要负责监听屏幕点击事件与界面绘制。当Application需要进行耗时 *** 作如网络请求等,如直接在主线程进行容易发生ANR错误。所以会创建子线程来执行耗时任务,当子线程执行完毕需要通知UI线程并修改界面时,不可以直接在子线程修改UI,怎么办?
解决方法:Message Queue机制可以实现子线程与UI线程的通信。
该机制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable对象 发给Looper,由它把消息放入所属线程的消息队列中,然后Looper又会自动把消息队列里的消息/Runnable对象 广播 到所属线程里的Handler,由Handler处理接收到的消息或Runnable对象。
1、Handler
每次创建Handler对象时,它会自动绑定到创建它的线程上。如果是主线程则默认包含一个Message Queue,否则需要自己创建一个消息队列来存储。
Handler是多个线程通信的信使。比如在线程A中创建AHandler,给它绑定一个ALooper,同时创建属于A的消息队列AMessageQueue。然后在线程B中使用AHandler发送消息给ALooper,ALooper会把消息存入到AMessageQueue,然后再把AMessageQueue广播给A线程里的AHandler,它接收到消息会进行处理。从而实现通信。
2、Message Queue
在主线程里默认包含了一个消息队列不需要手动创建。在子线程里,使用Looperprepare()方法后,会先检查子线程是否已有一个looper对象,如果有则无法创建,因为每个线程只能拥有一个消息队列。没有的话就为子线程创建一个消息队列。
Handler类包含Looper指针和MessageQueue指针,而Looper里包含实际MessageQueue与当前线程指针。
下面分别就UI线程和worker线程讲解handler创建过程:
首先,创建handler时,会自动检查当前线程是否包含looper对象,如果包含,则将handler内的消息队列指向looper内部的消息队列,否则,抛出异常请求执行looperprepare()方法。
- 在 UI线程 中,系统自动创建了Looper 对象,所以,直接new一个handler即可使用该机制;
- 在 worker线程 中,如果直接创建handler会抛出运行时异常-即通过查‘线程-value’映射表发现当前线程无looper对象。所以需要先调用Looperprepare()方法。在prepare方法里,利用ThreadLocal<Looper>对象为当前线程创建一个Looper(利用了一个Values类,即一个Map映射表,专为thread存储value,此处为当前thread存储一个looper对象)。然后继续创建handler, 让handler内部的消息队列指向该looper的消息队列(这个很重要,让handler指向looper里的消息队列,即二者共享同一个消息队列,然后handler向这个消息队列发送消息,looper从这个消息队列获取消息) 。然后looper循环消息队列即可。当获取到message消息,会找出message对象里的target,即原始发送handler,从而回调handler的handleMessage() 方法进行处理。
- handler与looper共享消息队列 ,所以handler发送消息只要入列,looper直接取消息即可。
- 线程与looper映射表 :一个线程最多可以映射一个looper对象。通过查表可知当前线程是否包含looper,如果已经包含则不再创建新looper。
5、基于这样的机制是怎样实现线程隔离的,即在线程中通信呢。
核心在于 每一个线程拥有自己的handler、message queue、looper体系 。而 每个线程的Handler是公开 的。B线程可以调用A线程的handler发送消息到A的共享消息队列去,然后A的looper会自动从共享消息队列取出消息进行处理。反之一样。
二、上面是基于子线程中利用主线程提供的Handler发送消息出去,然后主线程的Looper从消息队列中获取并处理。那么还有另外两种情况:
1、主线程发送消息到子线程中;
采用的方法和前面类似。要在子线程中实例化AHandler并设定处理消息的方法,同时由于子线程没有消息队列和Looper的轮询,所以要加上Looperprepare(),Looperloop()分别创建消息队列和开启轮询。然后在主线程中使用该AHandler去发送消息即可。
2、子线程A与子线程B之间的通信。
1、 Handler为什么能够实现不同线程的通信?核心点在哪?
不同线程之间,每个线程拥有自己的Handler、消息队列和Looper。Handler是公共的,线程可以通过使用目标线程的Handler对象来发送消息,这个消息会自动发送到所属线程的消息队列中去,线程自带的Looper对象会不断循环从里面取出消息并把消息发送给Handler,回调自身Handler的handlerMessage方法,从而实现了消息的线程间传递。
2、 Handler的核心是一种事件激活式(类似传递一个中断)的还是主要是用于传递大量数据的?重点在Message的内容,偏向于数据传输还是事件传输。
目前的理解,它所依赖的是消息队列,发送的自然是消息,即类似事件中断。
0、 Android消息处理机制(Handler、Looper、MessageQueue与Message)
1、 Handler、Looper源码阅读
2、 Android异步消息处理机制完全解析,带你从源码的角度彻底理解
谢谢!
wingjay
:如果数据源提供了API,可以通过API获取最新的数据。这种方式适用于数据更新频率较高的情况。
消息队列:可以使用消息队列来实现实时更新。当数据源有新数据时,将新数据发送到消息队列,爬虫程序从消息队列中获取数据。这种方式适用于数据更新频率很高,且需要实时处理数据的情况。
Webhook:Webhook是一种将事件通知发送到指定URL的机制。可以将数据源的更新事件配置为Webhook,当数据源有新数据时,将通知发送到指定URL,爬虫程序从该URL获取最新数据。这种方式适用于需要实时获取数据的情况。
需要注意的是,实时更新需要考虑到数据源的负载和网络带宽等因素。如果数据源更新频率很高,爬虫程序需要进行合理的限流和处理,以防止数据源的负载过高。同时,爬虫程序需要进行合理的缓存和数据处理,以便快速处理和展示最新的数据。
以上就是关于osqpend和osqpost怎么用全部的内容,包括:osqpend和osqpost怎么用、[Android源码分析] - 异步通信Handler机制、消息队列(mq)是什么等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)